xref: /dragonfly/contrib/gcc-8.0/gcc/cgraph.c (revision e215fc28)
138fd1498Szrj /* Callgraph handling code.
238fd1498Szrj    Copyright (C) 2003-2018 Free Software Foundation, Inc.
338fd1498Szrj    Contributed by Jan Hubicka
438fd1498Szrj 
538fd1498Szrj This file is part of GCC.
638fd1498Szrj 
738fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
838fd1498Szrj the terms of the GNU General Public License as published by the Free
938fd1498Szrj Software Foundation; either version 3, or (at your option) any later
1038fd1498Szrj version.
1138fd1498Szrj 
1238fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1338fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
1438fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1538fd1498Szrj for more details.
1638fd1498Szrj 
1738fd1498Szrj You should have received a copy of the GNU General Public License
1838fd1498Szrj along with GCC; see the file COPYING3.  If not see
1938fd1498Szrj <http://www.gnu.org/licenses/>.  */
2038fd1498Szrj 
2138fd1498Szrj /*  This file contains basic routines manipulating call graph
2238fd1498Szrj 
2338fd1498Szrj     The call-graph is a data structure designed for inter-procedural
2438fd1498Szrj     optimization.  It represents a multi-graph where nodes are functions
2538fd1498Szrj     (symbols within symbol table) and edges are call sites. */
2638fd1498Szrj 
2738fd1498Szrj #include "config.h"
2838fd1498Szrj #include "system.h"
2938fd1498Szrj #include "coretypes.h"
3038fd1498Szrj #include "backend.h"
3138fd1498Szrj #include "target.h"
3238fd1498Szrj #include "rtl.h"
3338fd1498Szrj #include "tree.h"
3438fd1498Szrj #include "gimple.h"
3538fd1498Szrj #include "predict.h"
3638fd1498Szrj #include "alloc-pool.h"
3738fd1498Szrj #include "gimple-ssa.h"
3838fd1498Szrj #include "cgraph.h"
3938fd1498Szrj #include "lto-streamer.h"
4038fd1498Szrj #include "fold-const.h"
4138fd1498Szrj #include "varasm.h"
4238fd1498Szrj #include "calls.h"
4338fd1498Szrj #include "print-tree.h"
4438fd1498Szrj #include "langhooks.h"
4538fd1498Szrj #include "intl.h"
4638fd1498Szrj #include "tree-eh.h"
4738fd1498Szrj #include "gimple-iterator.h"
4838fd1498Szrj #include "tree-cfg.h"
4938fd1498Szrj #include "tree-ssa.h"
5038fd1498Szrj #include "value-prof.h"
5138fd1498Szrj #include "ipa-utils.h"
5238fd1498Szrj #include "symbol-summary.h"
5338fd1498Szrj #include "tree-vrp.h"
5438fd1498Szrj #include "ipa-prop.h"
5538fd1498Szrj #include "ipa-fnsummary.h"
5638fd1498Szrj #include "cfgloop.h"
5738fd1498Szrj #include "gimple-pretty-print.h"
5838fd1498Szrj #include "tree-dfa.h"
5938fd1498Szrj #include "profile.h"
6038fd1498Szrj #include "params.h"
6138fd1498Szrj #include "tree-chkp.h"
6238fd1498Szrj #include "context.h"
6338fd1498Szrj #include "gimplify.h"
6438fd1498Szrj #include "stringpool.h"
6538fd1498Szrj #include "attribs.h"
6638fd1498Szrj 
6738fd1498Szrj /* FIXME: Only for PROP_loops, but cgraph shouldn't have to know about this.  */
6838fd1498Szrj #include "tree-pass.h"
6938fd1498Szrj 
7038fd1498Szrj /* Queue of cgraph nodes scheduled to be lowered.  */
7138fd1498Szrj symtab_node *x_cgraph_nodes_queue;
7238fd1498Szrj #define cgraph_nodes_queue ((cgraph_node *)x_cgraph_nodes_queue)
7338fd1498Szrj 
7438fd1498Szrj /* Symbol table global context.  */
7538fd1498Szrj symbol_table *symtab;
7638fd1498Szrj 
7738fd1498Szrj /* List of hooks triggered on cgraph_edge events.  */
7838fd1498Szrj struct cgraph_edge_hook_list {
7938fd1498Szrj   cgraph_edge_hook hook;
8038fd1498Szrj   void *data;
8138fd1498Szrj   struct cgraph_edge_hook_list *next;
8238fd1498Szrj };
8338fd1498Szrj 
8438fd1498Szrj /* List of hooks triggered on cgraph_node events.  */
8538fd1498Szrj struct cgraph_node_hook_list {
8638fd1498Szrj   cgraph_node_hook hook;
8738fd1498Szrj   void *data;
8838fd1498Szrj   struct cgraph_node_hook_list *next;
8938fd1498Szrj };
9038fd1498Szrj 
9138fd1498Szrj /* List of hooks triggered on events involving two cgraph_edges.  */
9238fd1498Szrj struct cgraph_2edge_hook_list {
9338fd1498Szrj   cgraph_2edge_hook hook;
9438fd1498Szrj   void *data;
9538fd1498Szrj   struct cgraph_2edge_hook_list *next;
9638fd1498Szrj };
9738fd1498Szrj 
9838fd1498Szrj /* List of hooks triggered on events involving two cgraph_nodes.  */
9938fd1498Szrj struct cgraph_2node_hook_list {
10038fd1498Szrj   cgraph_2node_hook hook;
10138fd1498Szrj   void *data;
10238fd1498Szrj   struct cgraph_2node_hook_list *next;
10338fd1498Szrj };
10438fd1498Szrj 
10538fd1498Szrj /* Hash descriptor for cgraph_function_version_info.  */
10638fd1498Szrj 
10738fd1498Szrj struct function_version_hasher : ggc_ptr_hash<cgraph_function_version_info>
10838fd1498Szrj {
10938fd1498Szrj   static hashval_t hash (cgraph_function_version_info *);
11038fd1498Szrj   static bool equal (cgraph_function_version_info *,
11138fd1498Szrj 		     cgraph_function_version_info *);
11238fd1498Szrj };
11338fd1498Szrj 
11438fd1498Szrj /* Map a cgraph_node to cgraph_function_version_info using this htab.
11538fd1498Szrj    The cgraph_function_version_info has a THIS_NODE field that is the
11638fd1498Szrj    corresponding cgraph_node..  */
11738fd1498Szrj 
11838fd1498Szrj static GTY(()) hash_table<function_version_hasher> *cgraph_fnver_htab = NULL;
11938fd1498Szrj 
12038fd1498Szrj /* Hash function for cgraph_fnver_htab.  */
12138fd1498Szrj hashval_t
hash(cgraph_function_version_info * ptr)12238fd1498Szrj function_version_hasher::hash (cgraph_function_version_info *ptr)
12338fd1498Szrj {
12438fd1498Szrj   int uid = ptr->this_node->uid;
12538fd1498Szrj   return (hashval_t)(uid);
12638fd1498Szrj }
12738fd1498Szrj 
12838fd1498Szrj /* eq function for cgraph_fnver_htab.  */
12938fd1498Szrj bool
equal(cgraph_function_version_info * n1,cgraph_function_version_info * n2)13038fd1498Szrj function_version_hasher::equal (cgraph_function_version_info *n1,
13138fd1498Szrj 			       	cgraph_function_version_info *n2)
13238fd1498Szrj {
13338fd1498Szrj   return n1->this_node->uid == n2->this_node->uid;
13438fd1498Szrj }
13538fd1498Szrj 
13638fd1498Szrj /* Mark as GC root all allocated nodes.  */
13738fd1498Szrj static GTY(()) struct cgraph_function_version_info *
13838fd1498Szrj   version_info_node = NULL;
13938fd1498Szrj 
14038fd1498Szrj /* Return true if NODE's address can be compared.  */
14138fd1498Szrj 
14238fd1498Szrj bool
address_can_be_compared_p()14338fd1498Szrj symtab_node::address_can_be_compared_p ()
14438fd1498Szrj {
14538fd1498Szrj   /* Address of virtual tables and functions is never compared.  */
14638fd1498Szrj   if (DECL_VIRTUAL_P (decl))
14738fd1498Szrj     return false;
14838fd1498Szrj   /* Address of C++ cdtors is never compared.  */
14938fd1498Szrj   if (is_a <cgraph_node *> (this)
15038fd1498Szrj       && (DECL_CXX_CONSTRUCTOR_P (decl)
15138fd1498Szrj 	  || DECL_CXX_DESTRUCTOR_P (decl)))
15238fd1498Szrj     return false;
15338fd1498Szrj   /* Constant pool symbols addresses are never compared.
15438fd1498Szrj      flag_merge_constants permits us to assume the same on readonly vars.  */
15538fd1498Szrj   if (is_a <varpool_node *> (this)
15638fd1498Szrj       && (DECL_IN_CONSTANT_POOL (decl)
15738fd1498Szrj 	  || (flag_merge_constants >= 2
15838fd1498Szrj 	      && TREE_READONLY (decl) && !TREE_THIS_VOLATILE (decl))))
15938fd1498Szrj     return false;
16038fd1498Szrj   return true;
16138fd1498Szrj }
16238fd1498Szrj 
16338fd1498Szrj /* Get the cgraph_function_version_info node corresponding to node.  */
16438fd1498Szrj cgraph_function_version_info *
function_version(void)16538fd1498Szrj cgraph_node::function_version (void)
16638fd1498Szrj {
16738fd1498Szrj   cgraph_function_version_info key;
16838fd1498Szrj   key.this_node = this;
16938fd1498Szrj 
17038fd1498Szrj   if (cgraph_fnver_htab == NULL)
17138fd1498Szrj     return NULL;
17238fd1498Szrj 
17338fd1498Szrj   return cgraph_fnver_htab->find (&key);
17438fd1498Szrj }
17538fd1498Szrj 
17638fd1498Szrj /* Insert a new cgraph_function_version_info node into cgraph_fnver_htab
17738fd1498Szrj    corresponding to cgraph_node NODE.  */
17838fd1498Szrj cgraph_function_version_info *
insert_new_function_version(void)17938fd1498Szrj cgraph_node::insert_new_function_version (void)
18038fd1498Szrj {
18138fd1498Szrj   version_info_node = NULL;
18238fd1498Szrj   version_info_node = ggc_cleared_alloc<cgraph_function_version_info> ();
18338fd1498Szrj   version_info_node->this_node = this;
18438fd1498Szrj 
18538fd1498Szrj   if (cgraph_fnver_htab == NULL)
18638fd1498Szrj     cgraph_fnver_htab = hash_table<function_version_hasher>::create_ggc (2);
18738fd1498Szrj 
18838fd1498Szrj   *cgraph_fnver_htab->find_slot (version_info_node, INSERT)
18938fd1498Szrj     = version_info_node;
19038fd1498Szrj   return version_info_node;
19138fd1498Szrj }
19238fd1498Szrj 
19338fd1498Szrj /* Remove the cgraph_function_version_info node given by DECL_V.  */
19438fd1498Szrj static void
delete_function_version(cgraph_function_version_info * decl_v)19538fd1498Szrj delete_function_version (cgraph_function_version_info *decl_v)
19638fd1498Szrj {
19738fd1498Szrj   if (decl_v == NULL)
19838fd1498Szrj     return;
19938fd1498Szrj 
20038fd1498Szrj   if (decl_v->prev != NULL)
20138fd1498Szrj     decl_v->prev->next = decl_v->next;
20238fd1498Szrj 
20338fd1498Szrj   if (decl_v->next != NULL)
20438fd1498Szrj     decl_v->next->prev = decl_v->prev;
20538fd1498Szrj 
20638fd1498Szrj   if (cgraph_fnver_htab != NULL)
20738fd1498Szrj     cgraph_fnver_htab->remove_elt (decl_v);
20838fd1498Szrj }
20938fd1498Szrj 
21038fd1498Szrj /* Remove the cgraph_function_version_info and cgraph_node for DECL.  This
21138fd1498Szrj    DECL is a duplicate declaration.  */
21238fd1498Szrj void
delete_function_version_by_decl(tree decl)21338fd1498Szrj cgraph_node::delete_function_version_by_decl (tree decl)
21438fd1498Szrj {
21538fd1498Szrj   cgraph_node *decl_node = cgraph_node::get (decl);
21638fd1498Szrj 
21738fd1498Szrj   if (decl_node == NULL)
21838fd1498Szrj     return;
21938fd1498Szrj 
22038fd1498Szrj   delete_function_version (decl_node->function_version ());
22138fd1498Szrj 
22238fd1498Szrj   decl_node->remove ();
22338fd1498Szrj }
22438fd1498Szrj 
22538fd1498Szrj /* Record that DECL1 and DECL2 are semantically identical function
22638fd1498Szrj    versions.  */
22738fd1498Szrj void
record_function_versions(tree decl1,tree decl2)22838fd1498Szrj cgraph_node::record_function_versions (tree decl1, tree decl2)
22938fd1498Szrj {
23038fd1498Szrj   cgraph_node *decl1_node = cgraph_node::get_create (decl1);
23138fd1498Szrj   cgraph_node *decl2_node = cgraph_node::get_create (decl2);
23238fd1498Szrj   cgraph_function_version_info *decl1_v = NULL;
23338fd1498Szrj   cgraph_function_version_info *decl2_v = NULL;
23438fd1498Szrj   cgraph_function_version_info *before;
23538fd1498Szrj   cgraph_function_version_info *after;
23638fd1498Szrj 
23738fd1498Szrj   gcc_assert (decl1_node != NULL && decl2_node != NULL);
23838fd1498Szrj   decl1_v = decl1_node->function_version ();
23938fd1498Szrj   decl2_v = decl2_node->function_version ();
24038fd1498Szrj 
24138fd1498Szrj   if (decl1_v != NULL && decl2_v != NULL)
24238fd1498Szrj     return;
24338fd1498Szrj 
24438fd1498Szrj   if (decl1_v == NULL)
24538fd1498Szrj     decl1_v = decl1_node->insert_new_function_version ();
24638fd1498Szrj 
24738fd1498Szrj   if (decl2_v == NULL)
24838fd1498Szrj     decl2_v = decl2_node->insert_new_function_version ();
24938fd1498Szrj 
25038fd1498Szrj   /* Chain decl2_v and decl1_v.  All semantically identical versions
25138fd1498Szrj      will be chained together.  */
25238fd1498Szrj 
25338fd1498Szrj   before = decl1_v;
25438fd1498Szrj   after = decl2_v;
25538fd1498Szrj 
25638fd1498Szrj   while (before->next != NULL)
25738fd1498Szrj     before = before->next;
25838fd1498Szrj 
25938fd1498Szrj   while (after->prev != NULL)
26038fd1498Szrj     after= after->prev;
26138fd1498Szrj 
26238fd1498Szrj   before->next = after;
26338fd1498Szrj   after->prev = before;
26438fd1498Szrj }
26538fd1498Szrj 
26638fd1498Szrj /* Initialize callgraph dump file.  */
26738fd1498Szrj 
26838fd1498Szrj void
initialize(void)26938fd1498Szrj symbol_table::initialize (void)
27038fd1498Szrj {
27138fd1498Szrj   if (!dump_file)
27238fd1498Szrj     dump_file = dump_begin (TDI_cgraph, NULL);
27338fd1498Szrj 
27438fd1498Szrj   if (!ipa_clones_dump_file)
27538fd1498Szrj     ipa_clones_dump_file = dump_begin (TDI_clones, NULL);
27638fd1498Szrj }
27738fd1498Szrj 
27838fd1498Szrj /* Allocate new callgraph node and insert it into basic data structures.  */
27938fd1498Szrj 
28038fd1498Szrj cgraph_node *
create_empty(void)28138fd1498Szrj symbol_table::create_empty (void)
28238fd1498Szrj {
28338fd1498Szrj   cgraph_node *node = allocate_cgraph_symbol ();
28438fd1498Szrj 
28538fd1498Szrj   node->type = SYMTAB_FUNCTION;
28638fd1498Szrj   node->frequency = NODE_FREQUENCY_NORMAL;
28738fd1498Szrj   node->count_materialization_scale = REG_BR_PROB_BASE;
28838fd1498Szrj   cgraph_count++;
28938fd1498Szrj 
29038fd1498Szrj   return node;
29138fd1498Szrj }
29238fd1498Szrj 
29338fd1498Szrj /* Register HOOK to be called with DATA on each removed edge.  */
29438fd1498Szrj cgraph_edge_hook_list *
add_edge_removal_hook(cgraph_edge_hook hook,void * data)29538fd1498Szrj symbol_table::add_edge_removal_hook (cgraph_edge_hook hook, void *data)
29638fd1498Szrj {
29738fd1498Szrj   cgraph_edge_hook_list *entry;
29838fd1498Szrj   cgraph_edge_hook_list **ptr = &m_first_edge_removal_hook;
29938fd1498Szrj 
30038fd1498Szrj   entry = (cgraph_edge_hook_list *) xmalloc (sizeof (*entry));
30138fd1498Szrj   entry->hook = hook;
30238fd1498Szrj   entry->data = data;
30338fd1498Szrj   entry->next = NULL;
30438fd1498Szrj   while (*ptr)
30538fd1498Szrj     ptr = &(*ptr)->next;
30638fd1498Szrj   *ptr = entry;
30738fd1498Szrj   return entry;
30838fd1498Szrj }
30938fd1498Szrj 
31038fd1498Szrj /* Remove ENTRY from the list of hooks called on removing edges.  */
31138fd1498Szrj void
remove_edge_removal_hook(cgraph_edge_hook_list * entry)31238fd1498Szrj symbol_table::remove_edge_removal_hook (cgraph_edge_hook_list *entry)
31338fd1498Szrj {
31438fd1498Szrj   cgraph_edge_hook_list **ptr = &m_first_edge_removal_hook;
31538fd1498Szrj 
31638fd1498Szrj   while (*ptr != entry)
31738fd1498Szrj     ptr = &(*ptr)->next;
31838fd1498Szrj   *ptr = entry->next;
31938fd1498Szrj   free (entry);
32038fd1498Szrj }
32138fd1498Szrj 
32238fd1498Szrj /* Call all edge removal hooks.  */
32338fd1498Szrj void
call_edge_removal_hooks(cgraph_edge * e)32438fd1498Szrj symbol_table::call_edge_removal_hooks (cgraph_edge *e)
32538fd1498Szrj {
32638fd1498Szrj   cgraph_edge_hook_list *entry = m_first_edge_removal_hook;
32738fd1498Szrj   while (entry)
32838fd1498Szrj   {
32938fd1498Szrj     entry->hook (e, entry->data);
33038fd1498Szrj     entry = entry->next;
33138fd1498Szrj   }
33238fd1498Szrj }
33338fd1498Szrj 
33438fd1498Szrj /* Register HOOK to be called with DATA on each removed node.  */
33538fd1498Szrj cgraph_node_hook_list *
add_cgraph_removal_hook(cgraph_node_hook hook,void * data)33638fd1498Szrj symbol_table::add_cgraph_removal_hook (cgraph_node_hook hook, void *data)
33738fd1498Szrj {
33838fd1498Szrj   cgraph_node_hook_list *entry;
33938fd1498Szrj   cgraph_node_hook_list **ptr = &m_first_cgraph_removal_hook;
34038fd1498Szrj 
34138fd1498Szrj   entry = (cgraph_node_hook_list *) xmalloc (sizeof (*entry));
34238fd1498Szrj   entry->hook = hook;
34338fd1498Szrj   entry->data = data;
34438fd1498Szrj   entry->next = NULL;
34538fd1498Szrj   while (*ptr)
34638fd1498Szrj     ptr = &(*ptr)->next;
34738fd1498Szrj   *ptr = entry;
34838fd1498Szrj   return entry;
34938fd1498Szrj }
35038fd1498Szrj 
35138fd1498Szrj /* Remove ENTRY from the list of hooks called on removing nodes.  */
35238fd1498Szrj void
remove_cgraph_removal_hook(cgraph_node_hook_list * entry)35338fd1498Szrj symbol_table::remove_cgraph_removal_hook (cgraph_node_hook_list *entry)
35438fd1498Szrj {
35538fd1498Szrj   cgraph_node_hook_list **ptr = &m_first_cgraph_removal_hook;
35638fd1498Szrj 
35738fd1498Szrj   while (*ptr != entry)
35838fd1498Szrj     ptr = &(*ptr)->next;
35938fd1498Szrj   *ptr = entry->next;
36038fd1498Szrj   free (entry);
36138fd1498Szrj }
36238fd1498Szrj 
36338fd1498Szrj /* Call all node removal hooks.  */
36438fd1498Szrj void
call_cgraph_removal_hooks(cgraph_node * node)36538fd1498Szrj symbol_table::call_cgraph_removal_hooks (cgraph_node *node)
36638fd1498Szrj {
36738fd1498Szrj   cgraph_node_hook_list *entry = m_first_cgraph_removal_hook;
36838fd1498Szrj   while (entry)
36938fd1498Szrj   {
37038fd1498Szrj     entry->hook (node, entry->data);
37138fd1498Szrj     entry = entry->next;
37238fd1498Szrj   }
37338fd1498Szrj }
37438fd1498Szrj 
37538fd1498Szrj /* Call all node removal hooks.  */
37638fd1498Szrj void
call_cgraph_insertion_hooks(cgraph_node * node)37738fd1498Szrj symbol_table::call_cgraph_insertion_hooks (cgraph_node *node)
37838fd1498Szrj {
37938fd1498Szrj   cgraph_node_hook_list *entry = m_first_cgraph_insertion_hook;
38038fd1498Szrj   while (entry)
38138fd1498Szrj   {
38238fd1498Szrj     entry->hook (node, entry->data);
38338fd1498Szrj     entry = entry->next;
38438fd1498Szrj   }
38538fd1498Szrj }
38638fd1498Szrj 
38738fd1498Szrj 
38838fd1498Szrj /* Register HOOK to be called with DATA on each inserted node.  */
38938fd1498Szrj cgraph_node_hook_list *
add_cgraph_insertion_hook(cgraph_node_hook hook,void * data)39038fd1498Szrj symbol_table::add_cgraph_insertion_hook (cgraph_node_hook hook, void *data)
39138fd1498Szrj {
39238fd1498Szrj   cgraph_node_hook_list *entry;
39338fd1498Szrj   cgraph_node_hook_list **ptr = &m_first_cgraph_insertion_hook;
39438fd1498Szrj 
39538fd1498Szrj   entry = (cgraph_node_hook_list *) xmalloc (sizeof (*entry));
39638fd1498Szrj   entry->hook = hook;
39738fd1498Szrj   entry->data = data;
39838fd1498Szrj   entry->next = NULL;
39938fd1498Szrj   while (*ptr)
40038fd1498Szrj     ptr = &(*ptr)->next;
40138fd1498Szrj   *ptr = entry;
40238fd1498Szrj   return entry;
40338fd1498Szrj }
40438fd1498Szrj 
40538fd1498Szrj /* Remove ENTRY from the list of hooks called on inserted nodes.  */
40638fd1498Szrj void
remove_cgraph_insertion_hook(cgraph_node_hook_list * entry)40738fd1498Szrj symbol_table::remove_cgraph_insertion_hook (cgraph_node_hook_list *entry)
40838fd1498Szrj {
40938fd1498Szrj   cgraph_node_hook_list **ptr = &m_first_cgraph_insertion_hook;
41038fd1498Szrj 
41138fd1498Szrj   while (*ptr != entry)
41238fd1498Szrj     ptr = &(*ptr)->next;
41338fd1498Szrj   *ptr = entry->next;
41438fd1498Szrj   free (entry);
41538fd1498Szrj }
41638fd1498Szrj 
41738fd1498Szrj /* Register HOOK to be called with DATA on each duplicated edge.  */
41838fd1498Szrj cgraph_2edge_hook_list *
add_edge_duplication_hook(cgraph_2edge_hook hook,void * data)41938fd1498Szrj symbol_table::add_edge_duplication_hook (cgraph_2edge_hook hook, void *data)
42038fd1498Szrj {
42138fd1498Szrj   cgraph_2edge_hook_list *entry;
42238fd1498Szrj   cgraph_2edge_hook_list **ptr = &m_first_edge_duplicated_hook;
42338fd1498Szrj 
42438fd1498Szrj   entry = (cgraph_2edge_hook_list *) xmalloc (sizeof (*entry));
42538fd1498Szrj   entry->hook = hook;
42638fd1498Szrj   entry->data = data;
42738fd1498Szrj   entry->next = NULL;
42838fd1498Szrj   while (*ptr)
42938fd1498Szrj     ptr = &(*ptr)->next;
43038fd1498Szrj   *ptr = entry;
43138fd1498Szrj   return entry;
43238fd1498Szrj }
43338fd1498Szrj 
43438fd1498Szrj /* Remove ENTRY from the list of hooks called on duplicating edges.  */
43538fd1498Szrj void
remove_edge_duplication_hook(cgraph_2edge_hook_list * entry)43638fd1498Szrj symbol_table::remove_edge_duplication_hook (cgraph_2edge_hook_list *entry)
43738fd1498Szrj {
43838fd1498Szrj   cgraph_2edge_hook_list **ptr = &m_first_edge_duplicated_hook;
43938fd1498Szrj 
44038fd1498Szrj   while (*ptr != entry)
44138fd1498Szrj     ptr = &(*ptr)->next;
44238fd1498Szrj   *ptr = entry->next;
44338fd1498Szrj   free (entry);
44438fd1498Szrj }
44538fd1498Szrj 
44638fd1498Szrj /* Call all edge duplication hooks.  */
44738fd1498Szrj void
call_edge_duplication_hooks(cgraph_edge * cs1,cgraph_edge * cs2)44838fd1498Szrj symbol_table::call_edge_duplication_hooks (cgraph_edge *cs1, cgraph_edge *cs2)
44938fd1498Szrj {
45038fd1498Szrj   cgraph_2edge_hook_list *entry = m_first_edge_duplicated_hook;
45138fd1498Szrj   while (entry)
45238fd1498Szrj   {
45338fd1498Szrj     entry->hook (cs1, cs2, entry->data);
45438fd1498Szrj     entry = entry->next;
45538fd1498Szrj   }
45638fd1498Szrj }
45738fd1498Szrj 
45838fd1498Szrj /* Register HOOK to be called with DATA on each duplicated node.  */
45938fd1498Szrj cgraph_2node_hook_list *
add_cgraph_duplication_hook(cgraph_2node_hook hook,void * data)46038fd1498Szrj symbol_table::add_cgraph_duplication_hook (cgraph_2node_hook hook, void *data)
46138fd1498Szrj {
46238fd1498Szrj   cgraph_2node_hook_list *entry;
46338fd1498Szrj   cgraph_2node_hook_list **ptr = &m_first_cgraph_duplicated_hook;
46438fd1498Szrj 
46538fd1498Szrj   entry = (cgraph_2node_hook_list *) xmalloc (sizeof (*entry));
46638fd1498Szrj   entry->hook = hook;
46738fd1498Szrj   entry->data = data;
46838fd1498Szrj   entry->next = NULL;
46938fd1498Szrj   while (*ptr)
47038fd1498Szrj     ptr = &(*ptr)->next;
47138fd1498Szrj   *ptr = entry;
47238fd1498Szrj   return entry;
47338fd1498Szrj }
47438fd1498Szrj 
47538fd1498Szrj /* Remove ENTRY from the list of hooks called on duplicating nodes.  */
47638fd1498Szrj void
remove_cgraph_duplication_hook(cgraph_2node_hook_list * entry)47738fd1498Szrj symbol_table::remove_cgraph_duplication_hook (cgraph_2node_hook_list *entry)
47838fd1498Szrj {
47938fd1498Szrj   cgraph_2node_hook_list **ptr = &m_first_cgraph_duplicated_hook;
48038fd1498Szrj 
48138fd1498Szrj   while (*ptr != entry)
48238fd1498Szrj     ptr = &(*ptr)->next;
48338fd1498Szrj   *ptr = entry->next;
48438fd1498Szrj   free (entry);
48538fd1498Szrj }
48638fd1498Szrj 
48738fd1498Szrj /* Call all node duplication hooks.  */
48838fd1498Szrj void
call_cgraph_duplication_hooks(cgraph_node * node,cgraph_node * node2)48938fd1498Szrj symbol_table::call_cgraph_duplication_hooks (cgraph_node *node,
49038fd1498Szrj 					     cgraph_node *node2)
49138fd1498Szrj {
49238fd1498Szrj   cgraph_2node_hook_list *entry = m_first_cgraph_duplicated_hook;
49338fd1498Szrj   while (entry)
49438fd1498Szrj   {
49538fd1498Szrj     entry->hook (node, node2, entry->data);
49638fd1498Szrj     entry = entry->next;
49738fd1498Szrj   }
49838fd1498Szrj }
49938fd1498Szrj 
50038fd1498Szrj /* Return cgraph node assigned to DECL.  Create new one when needed.  */
50138fd1498Szrj 
50238fd1498Szrj cgraph_node *
create(tree decl)50338fd1498Szrj cgraph_node::create (tree decl)
50438fd1498Szrj {
50538fd1498Szrj   cgraph_node *node = symtab->create_empty ();
50638fd1498Szrj   gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
50738fd1498Szrj 
50838fd1498Szrj   node->decl = decl;
50938fd1498Szrj 
51038fd1498Szrj   node->count = profile_count::uninitialized ();
51138fd1498Szrj 
51238fd1498Szrj   if ((flag_openacc || flag_openmp)
51338fd1498Szrj       && lookup_attribute ("omp declare target", DECL_ATTRIBUTES (decl)))
51438fd1498Szrj     {
51538fd1498Szrj       node->offloadable = 1;
51638fd1498Szrj       if (ENABLE_OFFLOADING)
51738fd1498Szrj 	g->have_offload = true;
51838fd1498Szrj     }
51938fd1498Szrj 
52058e805e6Szrj   if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (decl)))
52158e805e6Szrj     node->ifunc_resolver = true;
52258e805e6Szrj 
52338fd1498Szrj   node->register_symbol ();
52438fd1498Szrj 
52538fd1498Szrj   if (DECL_CONTEXT (decl) && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL)
52638fd1498Szrj     {
52738fd1498Szrj       node->origin = cgraph_node::get_create (DECL_CONTEXT (decl));
52838fd1498Szrj       node->next_nested = node->origin->nested;
52938fd1498Szrj       node->origin->nested = node;
53038fd1498Szrj     }
53138fd1498Szrj   return node;
53238fd1498Szrj }
53338fd1498Szrj 
53438fd1498Szrj /* Try to find a call graph node for declaration DECL and if it does not exist
53538fd1498Szrj    or if it corresponds to an inline clone, create a new one.  */
53638fd1498Szrj 
53738fd1498Szrj cgraph_node *
get_create(tree decl)53838fd1498Szrj cgraph_node::get_create (tree decl)
53938fd1498Szrj {
54038fd1498Szrj   cgraph_node *first_clone = cgraph_node::get (decl);
54138fd1498Szrj 
54238fd1498Szrj   if (first_clone && !first_clone->global.inlined_to)
54338fd1498Szrj     return first_clone;
54438fd1498Szrj 
54538fd1498Szrj   cgraph_node *node = cgraph_node::create (decl);
54638fd1498Szrj   if (first_clone)
54738fd1498Szrj     {
54838fd1498Szrj       first_clone->clone_of = node;
54938fd1498Szrj       node->clones = first_clone;
55038fd1498Szrj       symtab->symtab_prevail_in_asm_name_hash (node);
55138fd1498Szrj       node->decl->decl_with_vis.symtab_node = node;
55238fd1498Szrj       if (dump_file)
55338fd1498Szrj 	fprintf (dump_file, "Introduced new external node "
55438fd1498Szrj 		 "(%s) and turned into root of the clone tree.\n",
55538fd1498Szrj 		 node->dump_name ());
55638fd1498Szrj     }
55738fd1498Szrj   else if (dump_file)
55838fd1498Szrj     fprintf (dump_file, "Introduced new external node "
55938fd1498Szrj 	     "(%s).\n", node->dump_name ());
56038fd1498Szrj   return node;
56138fd1498Szrj }
56238fd1498Szrj 
56338fd1498Szrj /* Mark ALIAS as an alias to DECL.  DECL_NODE is cgraph node representing
56438fd1498Szrj    the function body is associated with (not necessarily cgraph_node (DECL).  */
56538fd1498Szrj 
56638fd1498Szrj cgraph_node *
create_alias(tree alias,tree target)56738fd1498Szrj cgraph_node::create_alias (tree alias, tree target)
56838fd1498Szrj {
56938fd1498Szrj   cgraph_node *alias_node;
57038fd1498Szrj 
57138fd1498Szrj   gcc_assert (TREE_CODE (target) == FUNCTION_DECL
57238fd1498Szrj 	      || TREE_CODE (target) == IDENTIFIER_NODE);
57338fd1498Szrj   gcc_assert (TREE_CODE (alias) == FUNCTION_DECL);
57438fd1498Szrj   alias_node = cgraph_node::get_create (alias);
57538fd1498Szrj   gcc_assert (!alias_node->definition);
57638fd1498Szrj   alias_node->alias_target = target;
57738fd1498Szrj   alias_node->definition = true;
57838fd1498Szrj   alias_node->alias = true;
57938fd1498Szrj   if (lookup_attribute ("weakref", DECL_ATTRIBUTES (alias)) != NULL)
58038fd1498Szrj     alias_node->transparent_alias = alias_node->weakref = true;
58158e805e6Szrj   if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (alias)))
58258e805e6Szrj     alias_node->ifunc_resolver = true;
58338fd1498Szrj   return alias_node;
58438fd1498Szrj }
58538fd1498Szrj 
58638fd1498Szrj /* Attempt to mark ALIAS as an alias to DECL.  Return alias node if successful
58738fd1498Szrj    and NULL otherwise.
58838fd1498Szrj    Same body aliases are output whenever the body of DECL is output,
58938fd1498Szrj    and cgraph_node::get (ALIAS) transparently returns
59038fd1498Szrj    cgraph_node::get (DECL).  */
59138fd1498Szrj 
59238fd1498Szrj cgraph_node *
create_same_body_alias(tree alias,tree decl)59338fd1498Szrj cgraph_node::create_same_body_alias (tree alias, tree decl)
59438fd1498Szrj {
59538fd1498Szrj   cgraph_node *n;
59638fd1498Szrj 
59738fd1498Szrj   /* If aliases aren't supported by the assembler, fail.  */
59838fd1498Szrj   if (!TARGET_SUPPORTS_ALIASES)
59938fd1498Szrj     return NULL;
60038fd1498Szrj 
60138fd1498Szrj   /* Langhooks can create same body aliases of symbols not defined.
60238fd1498Szrj      Those are useless. Drop them on the floor.  */
60338fd1498Szrj   if (symtab->global_info_ready)
60438fd1498Szrj     return NULL;
60538fd1498Szrj 
60638fd1498Szrj   n = cgraph_node::create_alias (alias, decl);
60738fd1498Szrj   n->cpp_implicit_alias = true;
60838fd1498Szrj   if (symtab->cpp_implicit_aliases_done)
60938fd1498Szrj     n->resolve_alias (cgraph_node::get (decl));
61038fd1498Szrj   return n;
61138fd1498Szrj }
61238fd1498Szrj 
61338fd1498Szrj /* Add thunk alias into callgraph.  The alias declaration is ALIAS and it
61438fd1498Szrj    aliases DECL with an adjustments made into the first parameter.
61538fd1498Szrj    See comments in struct cgraph_thunk_info for detail on the parameters.  */
61638fd1498Szrj 
61738fd1498Szrj cgraph_node *
create_thunk(tree alias,tree,bool this_adjusting,HOST_WIDE_INT fixed_offset,HOST_WIDE_INT virtual_value,tree virtual_offset,tree real_alias)61838fd1498Szrj cgraph_node::create_thunk (tree alias, tree, bool this_adjusting,
61938fd1498Szrj 			   HOST_WIDE_INT fixed_offset,
62038fd1498Szrj 			   HOST_WIDE_INT virtual_value,
62138fd1498Szrj 			   tree virtual_offset,
62238fd1498Szrj 			   tree real_alias)
62338fd1498Szrj {
62438fd1498Szrj   cgraph_node *node;
62538fd1498Szrj 
62638fd1498Szrj   node = cgraph_node::get (alias);
62738fd1498Szrj   if (node)
62838fd1498Szrj     node->reset ();
62938fd1498Szrj   else
63038fd1498Szrj     node = cgraph_node::create (alias);
63138fd1498Szrj 
63238fd1498Szrj   /* Make sure that if VIRTUAL_OFFSET is in sync with VIRTUAL_VALUE.  */
63338fd1498Szrj   gcc_checking_assert (virtual_offset
63438fd1498Szrj 		       ? virtual_value == wi::to_wide (virtual_offset)
63538fd1498Szrj 		       : virtual_value == 0);
63638fd1498Szrj 
63738fd1498Szrj   node->thunk.fixed_offset = fixed_offset;
63838fd1498Szrj   node->thunk.virtual_value = virtual_value;
63938fd1498Szrj   node->thunk.alias = real_alias;
64038fd1498Szrj   node->thunk.this_adjusting = this_adjusting;
64138fd1498Szrj   node->thunk.virtual_offset_p = virtual_offset != NULL;
64238fd1498Szrj   node->thunk.thunk_p = true;
64338fd1498Szrj   node->definition = true;
64438fd1498Szrj 
64538fd1498Szrj   return node;
64638fd1498Szrj }
64738fd1498Szrj 
64838fd1498Szrj /* Return the cgraph node that has ASMNAME for its DECL_ASSEMBLER_NAME.
64938fd1498Szrj    Return NULL if there's no such node.  */
65038fd1498Szrj 
65138fd1498Szrj cgraph_node *
get_for_asmname(tree asmname)65238fd1498Szrj cgraph_node::get_for_asmname (tree asmname)
65338fd1498Szrj {
65438fd1498Szrj   /* We do not want to look at inline clones.  */
65538fd1498Szrj   for (symtab_node *node = symtab_node::get_for_asmname (asmname);
65638fd1498Szrj        node;
65738fd1498Szrj        node = node->next_sharing_asm_name)
65838fd1498Szrj     {
65938fd1498Szrj       cgraph_node *cn = dyn_cast <cgraph_node *> (node);
66038fd1498Szrj       if (cn && !cn->global.inlined_to)
66138fd1498Szrj 	return cn;
66238fd1498Szrj     }
66338fd1498Szrj   return NULL;
66438fd1498Szrj }
66538fd1498Szrj 
66638fd1498Szrj /* Returns a hash value for X (which really is a cgraph_edge).  */
66738fd1498Szrj 
66838fd1498Szrj hashval_t
hash(cgraph_edge * e)66938fd1498Szrj cgraph_edge_hasher::hash (cgraph_edge *e)
67038fd1498Szrj {
67138fd1498Szrj   /* This is a really poor hash function, but it is what htab_hash_pointer
67238fd1498Szrj      uses.  */
67338fd1498Szrj   return (hashval_t) ((intptr_t)e->call_stmt >> 3);
67438fd1498Szrj }
67538fd1498Szrj 
67638fd1498Szrj /* Returns a hash value for X (which really is a cgraph_edge).  */
67738fd1498Szrj 
67838fd1498Szrj hashval_t
hash(gimple * call_stmt)67938fd1498Szrj cgraph_edge_hasher::hash (gimple *call_stmt)
68038fd1498Szrj {
68138fd1498Szrj   /* This is a really poor hash function, but it is what htab_hash_pointer
68238fd1498Szrj      uses.  */
68338fd1498Szrj   return (hashval_t) ((intptr_t)call_stmt >> 3);
68438fd1498Szrj }
68538fd1498Szrj 
68638fd1498Szrj /* Return nonzero if the call_stmt of cgraph_edge X is stmt *Y.  */
68738fd1498Szrj 
68838fd1498Szrj inline bool
equal(cgraph_edge * x,gimple * y)68938fd1498Szrj cgraph_edge_hasher::equal (cgraph_edge *x, gimple *y)
69038fd1498Szrj {
69138fd1498Szrj   return x->call_stmt == y;
69238fd1498Szrj }
69338fd1498Szrj 
69438fd1498Szrj /* Add call graph edge E to call site hash of its caller.  */
69538fd1498Szrj 
69638fd1498Szrj static inline void
cgraph_update_edge_in_call_site_hash(cgraph_edge * e)69738fd1498Szrj cgraph_update_edge_in_call_site_hash (cgraph_edge *e)
69838fd1498Szrj {
69938fd1498Szrj   gimple *call = e->call_stmt;
70038fd1498Szrj   *e->caller->call_site_hash->find_slot_with_hash
70138fd1498Szrj       (call, cgraph_edge_hasher::hash (call), INSERT) = e;
70238fd1498Szrj }
70338fd1498Szrj 
70438fd1498Szrj /* Add call graph edge E to call site hash of its caller.  */
70538fd1498Szrj 
70638fd1498Szrj static inline void
cgraph_add_edge_to_call_site_hash(cgraph_edge * e)70738fd1498Szrj cgraph_add_edge_to_call_site_hash (cgraph_edge *e)
70838fd1498Szrj {
70938fd1498Szrj   /* There are two speculative edges for every statement (one direct,
71038fd1498Szrj      one indirect); always hash the direct one.  */
71138fd1498Szrj   if (e->speculative && e->indirect_unknown_callee)
71238fd1498Szrj     return;
71338fd1498Szrj   cgraph_edge **slot = e->caller->call_site_hash->find_slot_with_hash
71438fd1498Szrj       (e->call_stmt, cgraph_edge_hasher::hash (e->call_stmt), INSERT);
71538fd1498Szrj   if (*slot)
71638fd1498Szrj     {
71738fd1498Szrj       gcc_assert (((cgraph_edge *)*slot)->speculative);
71838fd1498Szrj       if (e->callee)
71938fd1498Szrj 	*slot = e;
72038fd1498Szrj       return;
72138fd1498Szrj     }
72238fd1498Szrj   gcc_assert (!*slot || e->speculative);
72338fd1498Szrj   *slot = e;
72438fd1498Szrj }
72538fd1498Szrj 
72638fd1498Szrj /* Return the callgraph edge representing the GIMPLE_CALL statement
72738fd1498Szrj    CALL_STMT.  */
72838fd1498Szrj 
72938fd1498Szrj cgraph_edge *
get_edge(gimple * call_stmt)73038fd1498Szrj cgraph_node::get_edge (gimple *call_stmt)
73138fd1498Szrj {
73238fd1498Szrj   cgraph_edge *e, *e2;
73338fd1498Szrj   int n = 0;
73438fd1498Szrj 
73538fd1498Szrj   if (call_site_hash)
73638fd1498Szrj     return call_site_hash->find_with_hash
73738fd1498Szrj 	(call_stmt, cgraph_edge_hasher::hash (call_stmt));
73838fd1498Szrj 
73938fd1498Szrj   /* This loop may turn out to be performance problem.  In such case adding
74038fd1498Szrj      hashtables into call nodes with very many edges is probably best
74138fd1498Szrj      solution.  It is not good idea to add pointer into CALL_EXPR itself
74238fd1498Szrj      because we want to make possible having multiple cgraph nodes representing
74338fd1498Szrj      different clones of the same body before the body is actually cloned.  */
74438fd1498Szrj   for (e = callees; e; e = e->next_callee)
74538fd1498Szrj     {
74638fd1498Szrj       if (e->call_stmt == call_stmt)
74738fd1498Szrj 	break;
74838fd1498Szrj       n++;
74938fd1498Szrj     }
75038fd1498Szrj 
75138fd1498Szrj   if (!e)
75238fd1498Szrj     for (e = indirect_calls; e; e = e->next_callee)
75338fd1498Szrj       {
75438fd1498Szrj 	if (e->call_stmt == call_stmt)
75538fd1498Szrj 	  break;
75638fd1498Szrj 	n++;
75738fd1498Szrj       }
75838fd1498Szrj 
75938fd1498Szrj   if (n > 100)
76038fd1498Szrj     {
76138fd1498Szrj       call_site_hash = hash_table<cgraph_edge_hasher>::create_ggc (120);
76238fd1498Szrj       for (e2 = callees; e2; e2 = e2->next_callee)
76338fd1498Szrj 	cgraph_add_edge_to_call_site_hash (e2);
76438fd1498Szrj       for (e2 = indirect_calls; e2; e2 = e2->next_callee)
76538fd1498Szrj 	cgraph_add_edge_to_call_site_hash (e2);
76638fd1498Szrj     }
76738fd1498Szrj 
76838fd1498Szrj   return e;
76938fd1498Szrj }
77038fd1498Szrj 
77138fd1498Szrj 
77238fd1498Szrj /* Change field call_stmt of edge to NEW_STMT.
77338fd1498Szrj    If UPDATE_SPECULATIVE and E is any component of speculative
77438fd1498Szrj    edge, then update all components.  */
77538fd1498Szrj 
77638fd1498Szrj void
set_call_stmt(gcall * new_stmt,bool update_speculative)77738fd1498Szrj cgraph_edge::set_call_stmt (gcall *new_stmt, bool update_speculative)
77838fd1498Szrj {
77938fd1498Szrj   tree decl;
78038fd1498Szrj 
78138fd1498Szrj   /* Speculative edges has three component, update all of them
78238fd1498Szrj      when asked to.  */
78338fd1498Szrj   if (update_speculative && speculative)
78438fd1498Szrj     {
78538fd1498Szrj       cgraph_edge *direct, *indirect;
78638fd1498Szrj       ipa_ref *ref;
78738fd1498Szrj 
78838fd1498Szrj       speculative_call_info (direct, indirect, ref);
78938fd1498Szrj       direct->set_call_stmt (new_stmt, false);
79038fd1498Szrj       indirect->set_call_stmt (new_stmt, false);
79138fd1498Szrj       ref->stmt = new_stmt;
79238fd1498Szrj       return;
79338fd1498Szrj     }
79438fd1498Szrj 
79538fd1498Szrj   /* Only direct speculative edges go to call_site_hash.  */
79638fd1498Szrj   if (caller->call_site_hash
79738fd1498Szrj       && (!speculative || !indirect_unknown_callee))
79838fd1498Szrj     {
79938fd1498Szrj       caller->call_site_hash->remove_elt_with_hash
80038fd1498Szrj 	(call_stmt, cgraph_edge_hasher::hash (call_stmt));
80138fd1498Szrj     }
80238fd1498Szrj 
80338fd1498Szrj   cgraph_edge *e = this;
80438fd1498Szrj 
80538fd1498Szrj   call_stmt = new_stmt;
80638fd1498Szrj   if (indirect_unknown_callee
80738fd1498Szrj       && (decl = gimple_call_fndecl (new_stmt)))
80838fd1498Szrj     {
80938fd1498Szrj       /* Constant propagation (and possibly also inlining?) can turn an
81038fd1498Szrj 	 indirect call into a direct one.  */
81138fd1498Szrj       cgraph_node *new_callee = cgraph_node::get (decl);
81238fd1498Szrj 
81338fd1498Szrj       gcc_checking_assert (new_callee);
81438fd1498Szrj       e = make_direct (new_callee);
81538fd1498Szrj     }
81638fd1498Szrj 
81738fd1498Szrj   push_cfun (DECL_STRUCT_FUNCTION (e->caller->decl));
81838fd1498Szrj   e->can_throw_external = stmt_can_throw_external (new_stmt);
81938fd1498Szrj   pop_cfun ();
82038fd1498Szrj   if (e->caller->call_site_hash)
82138fd1498Szrj     cgraph_add_edge_to_call_site_hash (e);
82238fd1498Szrj }
82338fd1498Szrj 
82438fd1498Szrj /* Allocate a cgraph_edge structure and fill it with data according to the
82538fd1498Szrj    parameters of which only CALLEE can be NULL (when creating an indirect call
82638fd1498Szrj    edge).  */
82738fd1498Szrj 
82838fd1498Szrj cgraph_edge *
create_edge(cgraph_node * caller,cgraph_node * callee,gcall * call_stmt,profile_count count,bool indir_unknown_callee)82938fd1498Szrj symbol_table::create_edge (cgraph_node *caller, cgraph_node *callee,
83038fd1498Szrj 			   gcall *call_stmt, profile_count count,
83138fd1498Szrj 			   bool indir_unknown_callee)
83238fd1498Szrj {
83338fd1498Szrj   cgraph_edge *edge;
83438fd1498Szrj 
83538fd1498Szrj   /* LTO does not actually have access to the call_stmt since these
83638fd1498Szrj      have not been loaded yet.  */
83738fd1498Szrj   if (call_stmt)
83838fd1498Szrj     {
83938fd1498Szrj       /* This is a rather expensive check possibly triggering
84038fd1498Szrj 	 construction of call stmt hashtable.  */
84138fd1498Szrj       cgraph_edge *e;
84238fd1498Szrj       gcc_checking_assert (!(e = caller->get_edge (call_stmt))
84338fd1498Szrj 			   || e->speculative);
84438fd1498Szrj 
84538fd1498Szrj       gcc_assert (is_gimple_call (call_stmt));
84638fd1498Szrj     }
84738fd1498Szrj 
84838fd1498Szrj   if (free_edges)
84938fd1498Szrj     {
85038fd1498Szrj       edge = free_edges;
85138fd1498Szrj       free_edges = NEXT_FREE_EDGE (edge);
85238fd1498Szrj     }
85338fd1498Szrj   else
85438fd1498Szrj     {
85538fd1498Szrj       edge = ggc_alloc<cgraph_edge> ();
85638fd1498Szrj       edge->uid = edges_max_uid++;
85738fd1498Szrj     }
85838fd1498Szrj 
85938fd1498Szrj   edges_count++;
86038fd1498Szrj 
86138fd1498Szrj   edge->aux = NULL;
86238fd1498Szrj   edge->caller = caller;
86338fd1498Szrj   edge->callee = callee;
86438fd1498Szrj   edge->prev_caller = NULL;
86538fd1498Szrj   edge->next_caller = NULL;
86638fd1498Szrj   edge->prev_callee = NULL;
86738fd1498Szrj   edge->next_callee = NULL;
86838fd1498Szrj   edge->lto_stmt_uid = 0;
86938fd1498Szrj 
87038fd1498Szrj   edge->count = count;
87138fd1498Szrj 
87238fd1498Szrj   edge->call_stmt = call_stmt;
87338fd1498Szrj   push_cfun (DECL_STRUCT_FUNCTION (caller->decl));
87438fd1498Szrj   edge->can_throw_external
87538fd1498Szrj     = call_stmt ? stmt_can_throw_external (call_stmt) : false;
87638fd1498Szrj   pop_cfun ();
87738fd1498Szrj   if (call_stmt
87838fd1498Szrj       && callee && callee->decl
87938fd1498Szrj       && !gimple_check_call_matching_types (call_stmt, callee->decl,
88038fd1498Szrj 					    false))
88138fd1498Szrj     {
88238fd1498Szrj       edge->inline_failed = CIF_MISMATCHED_ARGUMENTS;
88338fd1498Szrj       edge->call_stmt_cannot_inline_p = true;
88438fd1498Szrj     }
88538fd1498Szrj   else
88638fd1498Szrj     {
88738fd1498Szrj       edge->inline_failed = CIF_FUNCTION_NOT_CONSIDERED;
88838fd1498Szrj       edge->call_stmt_cannot_inline_p = false;
88938fd1498Szrj     }
89038fd1498Szrj 
89138fd1498Szrj   edge->indirect_info = NULL;
89238fd1498Szrj   edge->indirect_inlining_edge = 0;
89338fd1498Szrj   edge->speculative = false;
89438fd1498Szrj   edge->indirect_unknown_callee = indir_unknown_callee;
89538fd1498Szrj   if (opt_for_fn (edge->caller->decl, flag_devirtualize)
89638fd1498Szrj       && call_stmt && DECL_STRUCT_FUNCTION (caller->decl))
89738fd1498Szrj     edge->in_polymorphic_cdtor
89838fd1498Szrj       = decl_maybe_in_construction_p (NULL, NULL, call_stmt,
89938fd1498Szrj 				      caller->decl);
90038fd1498Szrj   else
90138fd1498Szrj     edge->in_polymorphic_cdtor = caller->thunk.thunk_p;
90238fd1498Szrj   if (call_stmt && caller->call_site_hash)
90338fd1498Szrj     cgraph_add_edge_to_call_site_hash (edge);
90438fd1498Szrj 
90538fd1498Szrj   return edge;
90638fd1498Szrj }
90738fd1498Szrj 
90838fd1498Szrj /* Create edge from a given function to CALLEE in the cgraph.  */
90938fd1498Szrj 
91038fd1498Szrj cgraph_edge *
create_edge(cgraph_node * callee,gcall * call_stmt,profile_count count)91138fd1498Szrj cgraph_node::create_edge (cgraph_node *callee,
91238fd1498Szrj 			  gcall *call_stmt, profile_count count)
91338fd1498Szrj {
91438fd1498Szrj   cgraph_edge *edge = symtab->create_edge (this, callee, call_stmt, count,
91538fd1498Szrj 					   false);
91638fd1498Szrj 
91738fd1498Szrj   initialize_inline_failed (edge);
91838fd1498Szrj 
91938fd1498Szrj   edge->next_caller = callee->callers;
92038fd1498Szrj   if (callee->callers)
92138fd1498Szrj     callee->callers->prev_caller = edge;
92238fd1498Szrj   edge->next_callee = callees;
92338fd1498Szrj   if (callees)
92438fd1498Szrj     callees->prev_callee = edge;
92538fd1498Szrj   callees = edge;
92638fd1498Szrj   callee->callers = edge;
92738fd1498Szrj 
92838fd1498Szrj   return edge;
92938fd1498Szrj }
93038fd1498Szrj 
93138fd1498Szrj /* Allocate cgraph_indirect_call_info and set its fields to default values. */
93238fd1498Szrj 
93338fd1498Szrj cgraph_indirect_call_info *
cgraph_allocate_init_indirect_info(void)93438fd1498Szrj cgraph_allocate_init_indirect_info (void)
93538fd1498Szrj {
93638fd1498Szrj   cgraph_indirect_call_info *ii;
93738fd1498Szrj 
93838fd1498Szrj   ii = ggc_cleared_alloc<cgraph_indirect_call_info> ();
93938fd1498Szrj   ii->param_index = -1;
94038fd1498Szrj   return ii;
94138fd1498Szrj }
94238fd1498Szrj 
94338fd1498Szrj /* Create an indirect edge with a yet-undetermined callee where the call
94438fd1498Szrj    statement destination is a formal parameter of the caller with index
94538fd1498Szrj    PARAM_INDEX. */
94638fd1498Szrj 
94738fd1498Szrj cgraph_edge *
create_indirect_edge(gcall * call_stmt,int ecf_flags,profile_count count,bool compute_indirect_info)94838fd1498Szrj cgraph_node::create_indirect_edge (gcall *call_stmt, int ecf_flags,
94938fd1498Szrj 				   profile_count count,
95038fd1498Szrj 				   bool compute_indirect_info)
95138fd1498Szrj {
95238fd1498Szrj   cgraph_edge *edge = symtab->create_edge (this, NULL, call_stmt,
95338fd1498Szrj 							    count, true);
95438fd1498Szrj   tree target;
95538fd1498Szrj 
95638fd1498Szrj   initialize_inline_failed (edge);
95738fd1498Szrj 
95838fd1498Szrj   edge->indirect_info = cgraph_allocate_init_indirect_info ();
95938fd1498Szrj   edge->indirect_info->ecf_flags = ecf_flags;
96038fd1498Szrj   edge->indirect_info->vptr_changed = true;
96138fd1498Szrj 
96238fd1498Szrj   /* Record polymorphic call info.  */
96338fd1498Szrj   if (compute_indirect_info
96438fd1498Szrj       && call_stmt
96538fd1498Szrj       && (target = gimple_call_fn (call_stmt))
96638fd1498Szrj       && virtual_method_call_p (target))
96738fd1498Szrj     {
96838fd1498Szrj       ipa_polymorphic_call_context context (decl, target, call_stmt);
96938fd1498Szrj 
97038fd1498Szrj       /* Only record types can have virtual calls.  */
97138fd1498Szrj       edge->indirect_info->polymorphic = true;
97238fd1498Szrj       edge->indirect_info->param_index = -1;
97338fd1498Szrj       edge->indirect_info->otr_token
97438fd1498Szrj 	 = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (target));
97538fd1498Szrj       edge->indirect_info->otr_type = obj_type_ref_class (target);
97638fd1498Szrj       gcc_assert (TREE_CODE (edge->indirect_info->otr_type) == RECORD_TYPE);
97738fd1498Szrj       edge->indirect_info->context = context;
97838fd1498Szrj     }
97938fd1498Szrj 
98038fd1498Szrj   edge->next_callee = indirect_calls;
98138fd1498Szrj   if (indirect_calls)
98238fd1498Szrj     indirect_calls->prev_callee = edge;
98338fd1498Szrj   indirect_calls = edge;
98438fd1498Szrj 
98538fd1498Szrj   return edge;
98638fd1498Szrj }
98738fd1498Szrj 
98838fd1498Szrj /* Remove the edge from the list of the callees of the caller.  */
98938fd1498Szrj 
99038fd1498Szrj void
remove_caller(void)99138fd1498Szrj cgraph_edge::remove_caller (void)
99238fd1498Szrj {
99338fd1498Szrj   if (prev_callee)
99438fd1498Szrj     prev_callee->next_callee = next_callee;
99538fd1498Szrj   if (next_callee)
99638fd1498Szrj     next_callee->prev_callee = prev_callee;
99738fd1498Szrj   if (!prev_callee)
99838fd1498Szrj     {
99938fd1498Szrj       if (indirect_unknown_callee)
100038fd1498Szrj 	caller->indirect_calls = next_callee;
100138fd1498Szrj       else
100238fd1498Szrj 	caller->callees = next_callee;
100338fd1498Szrj     }
100438fd1498Szrj   if (caller->call_site_hash)
100538fd1498Szrj     caller->call_site_hash->remove_elt_with_hash
100638fd1498Szrj 	(call_stmt, cgraph_edge_hasher::hash (call_stmt));
100738fd1498Szrj }
100838fd1498Szrj 
100938fd1498Szrj /* Put the edge onto the free list.  */
101038fd1498Szrj 
101138fd1498Szrj void
free_edge(cgraph_edge * e)101238fd1498Szrj symbol_table::free_edge (cgraph_edge *e)
101338fd1498Szrj {
101438fd1498Szrj   int uid = e->uid;
101538fd1498Szrj 
101638fd1498Szrj   if (e->indirect_info)
101738fd1498Szrj     ggc_free (e->indirect_info);
101838fd1498Szrj 
101938fd1498Szrj   /* Clear out the edge so we do not dangle pointers.  */
102038fd1498Szrj   memset (e, 0, sizeof (*e));
102138fd1498Szrj   e->uid = uid;
102238fd1498Szrj   NEXT_FREE_EDGE (e) = free_edges;
102338fd1498Szrj   free_edges = e;
102438fd1498Szrj   edges_count--;
102538fd1498Szrj }
102638fd1498Szrj 
102738fd1498Szrj /* Remove the edge in the cgraph.  */
102838fd1498Szrj 
102938fd1498Szrj void
remove(void)103038fd1498Szrj cgraph_edge::remove (void)
103138fd1498Szrj {
103238fd1498Szrj   /* Call all edge removal hooks.  */
103338fd1498Szrj   symtab->call_edge_removal_hooks (this);
103438fd1498Szrj 
103538fd1498Szrj   if (!indirect_unknown_callee)
103638fd1498Szrj     /* Remove from callers list of the callee.  */
103738fd1498Szrj     remove_callee ();
103838fd1498Szrj 
103938fd1498Szrj   /* Remove from callees list of the callers.  */
104038fd1498Szrj   remove_caller ();
104138fd1498Szrj 
104238fd1498Szrj   /* Put the edge onto the free list.  */
104338fd1498Szrj   symtab->free_edge (this);
104438fd1498Szrj }
104538fd1498Szrj 
104638fd1498Szrj /* Turn edge into speculative call calling N2. Update
104738fd1498Szrj    the profile so the direct call is taken COUNT times
104838fd1498Szrj    with FREQUENCY.
104938fd1498Szrj 
105038fd1498Szrj    At clone materialization time, the indirect call E will
105138fd1498Szrj    be expanded as:
105238fd1498Szrj 
105338fd1498Szrj    if (call_dest == N2)
105438fd1498Szrj      n2 ();
105538fd1498Szrj    else
105638fd1498Szrj      call call_dest
105738fd1498Szrj 
105838fd1498Szrj    At this time the function just creates the direct call,
105938fd1498Szrj    the referencd representing the if conditional and attaches
106038fd1498Szrj    them all to the orginal indirect call statement.
106138fd1498Szrj 
106238fd1498Szrj    Return direct edge created.  */
106338fd1498Szrj 
106438fd1498Szrj cgraph_edge *
make_speculative(cgraph_node * n2,profile_count direct_count)106538fd1498Szrj cgraph_edge::make_speculative (cgraph_node *n2, profile_count direct_count)
106638fd1498Szrj {
106738fd1498Szrj   cgraph_node *n = caller;
106838fd1498Szrj   ipa_ref *ref = NULL;
106938fd1498Szrj   cgraph_edge *e2;
107038fd1498Szrj 
107138fd1498Szrj   if (dump_file)
107238fd1498Szrj     fprintf (dump_file, "Indirect call -> speculative call %s => %s\n",
107338fd1498Szrj 	     n->dump_name (), n2->dump_name ());
107438fd1498Szrj   speculative = true;
107538fd1498Szrj   e2 = n->create_edge (n2, call_stmt, direct_count);
107638fd1498Szrj   initialize_inline_failed (e2);
107738fd1498Szrj   e2->speculative = true;
107838fd1498Szrj   if (TREE_NOTHROW (n2->decl))
107938fd1498Szrj     e2->can_throw_external = false;
108038fd1498Szrj   else
108138fd1498Szrj     e2->can_throw_external = can_throw_external;
108238fd1498Szrj   e2->lto_stmt_uid = lto_stmt_uid;
108338fd1498Szrj   e2->in_polymorphic_cdtor = in_polymorphic_cdtor;
108438fd1498Szrj   count -= e2->count;
108538fd1498Szrj   symtab->call_edge_duplication_hooks (this, e2);
108638fd1498Szrj   ref = n->create_reference (n2, IPA_REF_ADDR, call_stmt);
108738fd1498Szrj   ref->lto_stmt_uid = lto_stmt_uid;
108838fd1498Szrj   ref->speculative = speculative;
108938fd1498Szrj   n2->mark_address_taken ();
109038fd1498Szrj   return e2;
109138fd1498Szrj }
109238fd1498Szrj 
109338fd1498Szrj /* Speculative call consist of three components:
109438fd1498Szrj    1) an indirect edge representing the original call
109538fd1498Szrj    2) an direct edge representing the new call
109638fd1498Szrj    3) ADDR_EXPR reference representing the speculative check.
109738fd1498Szrj    All three components are attached to single statement (the indirect
109838fd1498Szrj    call) and if one of them exists, all of them must exist.
109938fd1498Szrj 
110038fd1498Szrj    Given speculative call edge, return all three components.
110138fd1498Szrj  */
110238fd1498Szrj 
110338fd1498Szrj void
speculative_call_info(cgraph_edge * & direct,cgraph_edge * & indirect,ipa_ref * & reference)110438fd1498Szrj cgraph_edge::speculative_call_info (cgraph_edge *&direct,
110538fd1498Szrj 				    cgraph_edge *&indirect,
110638fd1498Szrj 				    ipa_ref *&reference)
110738fd1498Szrj {
110838fd1498Szrj   ipa_ref *ref;
110938fd1498Szrj   int i;
111038fd1498Szrj   cgraph_edge *e2;
111138fd1498Szrj   cgraph_edge *e = this;
111238fd1498Szrj 
111338fd1498Szrj   if (!e->indirect_unknown_callee)
111438fd1498Szrj     for (e2 = e->caller->indirect_calls;
111538fd1498Szrj 	 e2->call_stmt != e->call_stmt || e2->lto_stmt_uid != e->lto_stmt_uid;
111638fd1498Szrj 	 e2 = e2->next_callee)
111738fd1498Szrj       ;
111838fd1498Szrj   else
111938fd1498Szrj     {
112038fd1498Szrj       e2 = e;
112138fd1498Szrj       /* We can take advantage of the call stmt hash.  */
112238fd1498Szrj       if (e2->call_stmt)
112338fd1498Szrj 	{
112438fd1498Szrj 	  e = e->caller->get_edge (e2->call_stmt);
112538fd1498Szrj 	  gcc_assert (e->speculative && !e->indirect_unknown_callee);
112638fd1498Szrj 	}
112738fd1498Szrj       else
112838fd1498Szrj 	for (e = e->caller->callees;
112938fd1498Szrj 	     e2->call_stmt != e->call_stmt
113038fd1498Szrj 	     || e2->lto_stmt_uid != e->lto_stmt_uid;
113138fd1498Szrj 	     e = e->next_callee)
113238fd1498Szrj 	  ;
113338fd1498Szrj     }
113438fd1498Szrj   gcc_assert (e->speculative && e2->speculative);
113538fd1498Szrj   direct = e;
113638fd1498Szrj   indirect = e2;
113738fd1498Szrj 
113838fd1498Szrj   reference = NULL;
113938fd1498Szrj   for (i = 0; e->caller->iterate_reference (i, ref); i++)
114038fd1498Szrj     if (ref->speculative
114138fd1498Szrj 	&& ((ref->stmt && ref->stmt == e->call_stmt)
114238fd1498Szrj 	    || (!ref->stmt && ref->lto_stmt_uid == e->lto_stmt_uid)))
114338fd1498Szrj       {
114438fd1498Szrj 	reference = ref;
114538fd1498Szrj 	break;
114638fd1498Szrj       }
114738fd1498Szrj 
114838fd1498Szrj   /* Speculative edge always consist of all three components - direct edge,
114938fd1498Szrj      indirect and reference.  */
115038fd1498Szrj 
115138fd1498Szrj   gcc_assert (e && e2 && ref);
115238fd1498Szrj }
115338fd1498Szrj 
115438fd1498Szrj /* Speculative call edge turned out to be direct call to CALLE_DECL.
115538fd1498Szrj    Remove the speculative call sequence and return edge representing the call.
115638fd1498Szrj    It is up to caller to redirect the call as appropriate. */
115738fd1498Szrj 
115838fd1498Szrj cgraph_edge *
resolve_speculation(tree callee_decl)115938fd1498Szrj cgraph_edge::resolve_speculation (tree callee_decl)
116038fd1498Szrj {
116138fd1498Szrj   cgraph_edge *edge = this;
116238fd1498Szrj   cgraph_edge *e2;
116338fd1498Szrj   ipa_ref *ref;
116438fd1498Szrj 
116538fd1498Szrj   gcc_assert (edge->speculative);
116638fd1498Szrj   edge->speculative_call_info (e2, edge, ref);
116738fd1498Szrj   if (!callee_decl
116838fd1498Szrj       || !ref->referred->semantically_equivalent_p
116938fd1498Szrj 	   (symtab_node::get (callee_decl)))
117038fd1498Szrj     {
117138fd1498Szrj       if (dump_file)
117238fd1498Szrj 	{
117338fd1498Szrj 	  if (callee_decl)
117438fd1498Szrj 	    {
117538fd1498Szrj 	      fprintf (dump_file, "Speculative indirect call %s => %s has "
117638fd1498Szrj 		       "turned out to have contradicting known target ",
117738fd1498Szrj 		       edge->caller->dump_name (),
117838fd1498Szrj 		       e2->callee->dump_name ());
117938fd1498Szrj 	      print_generic_expr (dump_file, callee_decl);
118038fd1498Szrj 	      fprintf (dump_file, "\n");
118138fd1498Szrj 	    }
118238fd1498Szrj 	  else
118338fd1498Szrj 	    {
118438fd1498Szrj 	      fprintf (dump_file, "Removing speculative call %s => %s\n",
118538fd1498Szrj 		       edge->caller->dump_name (),
118638fd1498Szrj 		       e2->callee->dump_name ());
118738fd1498Szrj 	    }
118838fd1498Szrj 	}
118938fd1498Szrj     }
119038fd1498Szrj   else
119138fd1498Szrj     {
119238fd1498Szrj       cgraph_edge *tmp = edge;
119338fd1498Szrj       if (dump_file)
119438fd1498Szrj         fprintf (dump_file, "Speculative call turned into direct call.\n");
119538fd1498Szrj       edge = e2;
119638fd1498Szrj       e2 = tmp;
119738fd1498Szrj       /* FIXME:  If EDGE is inlined, we should scale up the frequencies and counts
119838fd1498Szrj          in the functions inlined through it.  */
119938fd1498Szrj     }
120038fd1498Szrj   edge->count += e2->count;
120138fd1498Szrj   edge->speculative = false;
120238fd1498Szrj   e2->speculative = false;
120338fd1498Szrj   ref->remove_reference ();
120438fd1498Szrj   if (e2->indirect_unknown_callee || e2->inline_failed)
120538fd1498Szrj     e2->remove ();
120638fd1498Szrj   else
120738fd1498Szrj     e2->callee->remove_symbol_and_inline_clones ();
120838fd1498Szrj   if (edge->caller->call_site_hash)
120938fd1498Szrj     cgraph_update_edge_in_call_site_hash (edge);
121038fd1498Szrj   return edge;
121138fd1498Szrj }
121238fd1498Szrj 
121338fd1498Szrj /* Make an indirect edge with an unknown callee an ordinary edge leading to
121438fd1498Szrj    CALLEE.  DELTA is an integer constant that is to be added to the this
121538fd1498Szrj    pointer (first parameter) to compensate for skipping a thunk adjustment.  */
121638fd1498Szrj 
121738fd1498Szrj cgraph_edge *
make_direct(cgraph_node * callee)121838fd1498Szrj cgraph_edge::make_direct (cgraph_node *callee)
121938fd1498Szrj {
122038fd1498Szrj   cgraph_edge *edge = this;
122138fd1498Szrj   gcc_assert (indirect_unknown_callee);
122238fd1498Szrj 
122338fd1498Szrj   /* If we are redirecting speculative call, make it non-speculative.  */
122438fd1498Szrj   if (indirect_unknown_callee && speculative)
122538fd1498Szrj     {
122638fd1498Szrj       edge = edge->resolve_speculation (callee->decl);
122738fd1498Szrj 
122838fd1498Szrj       /* On successful speculation just return the pre existing direct edge.  */
122938fd1498Szrj       if (!indirect_unknown_callee)
123038fd1498Szrj         return edge;
123138fd1498Szrj     }
123238fd1498Szrj 
123338fd1498Szrj   indirect_unknown_callee = 0;
123438fd1498Szrj   ggc_free (indirect_info);
123538fd1498Szrj   indirect_info = NULL;
123638fd1498Szrj 
123738fd1498Szrj   /* Get the edge out of the indirect edge list. */
123838fd1498Szrj   if (prev_callee)
123938fd1498Szrj     prev_callee->next_callee = next_callee;
124038fd1498Szrj   if (next_callee)
124138fd1498Szrj     next_callee->prev_callee = prev_callee;
124238fd1498Szrj   if (!prev_callee)
124338fd1498Szrj     caller->indirect_calls = next_callee;
124438fd1498Szrj 
124538fd1498Szrj   /* Put it into the normal callee list */
124638fd1498Szrj   prev_callee = NULL;
124738fd1498Szrj   next_callee = caller->callees;
124838fd1498Szrj   if (caller->callees)
124938fd1498Szrj     caller->callees->prev_callee = edge;
125038fd1498Szrj   caller->callees = edge;
125138fd1498Szrj 
125238fd1498Szrj   /* Insert to callers list of the new callee.  */
125338fd1498Szrj   edge->set_callee (callee);
125438fd1498Szrj 
125538fd1498Szrj   if (call_stmt
125638fd1498Szrj       && !gimple_check_call_matching_types (call_stmt, callee->decl, false))
125738fd1498Szrj     {
125838fd1498Szrj       call_stmt_cannot_inline_p = true;
125938fd1498Szrj       inline_failed = CIF_MISMATCHED_ARGUMENTS;
126038fd1498Szrj     }
126138fd1498Szrj 
126238fd1498Szrj   /* We need to re-determine the inlining status of the edge.  */
126338fd1498Szrj   initialize_inline_failed (edge);
126438fd1498Szrj   return edge;
126538fd1498Szrj }
126638fd1498Szrj 
126738fd1498Szrj /* If necessary, change the function declaration in the call statement
126838fd1498Szrj    associated with E so that it corresponds to the edge callee.  */
126938fd1498Szrj 
127038fd1498Szrj gimple *
redirect_call_stmt_to_callee(void)127138fd1498Szrj cgraph_edge::redirect_call_stmt_to_callee (void)
127238fd1498Szrj {
127338fd1498Szrj   cgraph_edge *e = this;
127438fd1498Szrj 
127538fd1498Szrj   tree decl = gimple_call_fndecl (e->call_stmt);
127638fd1498Szrj   gcall *new_stmt;
127738fd1498Szrj   gimple_stmt_iterator gsi;
127838fd1498Szrj   bool skip_bounds = false;
127938fd1498Szrj 
128038fd1498Szrj   if (e->speculative)
128138fd1498Szrj     {
128238fd1498Szrj       cgraph_edge *e2;
128338fd1498Szrj       gcall *new_stmt;
128438fd1498Szrj       ipa_ref *ref;
128538fd1498Szrj 
128638fd1498Szrj       e->speculative_call_info (e, e2, ref);
128738fd1498Szrj       /* If there already is an direct call (i.e. as a result of inliner's
128838fd1498Szrj 	 substitution), forget about speculating.  */
128938fd1498Szrj       if (decl)
129038fd1498Szrj 	e = e->resolve_speculation (decl);
129138fd1498Szrj       /* If types do not match, speculation was likely wrong.
129238fd1498Szrj          The direct edge was possibly redirected to the clone with a different
129338fd1498Szrj 	 signature.  We did not update the call statement yet, so compare it
129438fd1498Szrj 	 with the reference that still points to the proper type.  */
129538fd1498Szrj       else if (!gimple_check_call_matching_types (e->call_stmt,
129638fd1498Szrj 						  ref->referred->decl,
129738fd1498Szrj 						  true))
129838fd1498Szrj 	{
129938fd1498Szrj 	  if (dump_file)
130038fd1498Szrj 	    fprintf (dump_file, "Not expanding speculative call of %s -> %s\n"
130138fd1498Szrj 		     "Type mismatch.\n",
130238fd1498Szrj 		     e->caller->dump_name (),
130338fd1498Szrj 		     e->callee->dump_name ());
130438fd1498Szrj 	  e = e->resolve_speculation ();
130538fd1498Szrj 	  /* We are producing the final function body and will throw away the
130638fd1498Szrj 	     callgraph edges really soon.  Reset the counts/frequencies to
130738fd1498Szrj 	     keep verifier happy in the case of roundoff errors.  */
130838fd1498Szrj 	  e->count = gimple_bb (e->call_stmt)->count;
130938fd1498Szrj 	}
131038fd1498Szrj       /* Expand speculation into GIMPLE code.  */
131138fd1498Szrj       else
131238fd1498Szrj 	{
131338fd1498Szrj 	  if (dump_file)
131438fd1498Szrj 	    {
131538fd1498Szrj 	      fprintf (dump_file,
131638fd1498Szrj 		       "Expanding speculative call of %s -> %s count: ",
131738fd1498Szrj 		       e->caller->dump_name (),
131838fd1498Szrj 		       e->callee->dump_name ());
131938fd1498Szrj 	      e->count.dump (dump_file);
132038fd1498Szrj 	      fprintf (dump_file, "\n");
132138fd1498Szrj 	    }
132238fd1498Szrj 	  gcc_assert (e2->speculative);
132338fd1498Szrj 	  push_cfun (DECL_STRUCT_FUNCTION (e->caller->decl));
132438fd1498Szrj 
132538fd1498Szrj 	  profile_probability prob = e->count.probability_in (e->count
132638fd1498Szrj 							      + e2->count);
132738fd1498Szrj 	  if (!prob.initialized_p ())
132838fd1498Szrj 	    prob = profile_probability::even ();
132938fd1498Szrj 	  new_stmt = gimple_ic (e->call_stmt,
133038fd1498Szrj 				dyn_cast<cgraph_node *> (ref->referred),
133138fd1498Szrj 				prob);
133238fd1498Szrj 	  e->speculative = false;
133338fd1498Szrj 	  e->caller->set_call_stmt_including_clones (e->call_stmt, new_stmt,
133438fd1498Szrj 						     false);
133538fd1498Szrj 	  e->count = gimple_bb (e->call_stmt)->count;
133638fd1498Szrj 
133738fd1498Szrj 	  /* Fix edges for BUILT_IN_CHKP_BNDRET calls attached to the
133838fd1498Szrj 	     processed call stmt.  */
133938fd1498Szrj 	  if (gimple_call_with_bounds_p (new_stmt)
134038fd1498Szrj 	      && gimple_call_lhs (new_stmt)
134138fd1498Szrj 	      && chkp_retbnd_call_by_val (gimple_call_lhs (e2->call_stmt)))
134238fd1498Szrj 	    {
134338fd1498Szrj 	      tree dresult = gimple_call_lhs (new_stmt);
134438fd1498Szrj 	      tree iresult = gimple_call_lhs (e2->call_stmt);
134538fd1498Szrj 	      gcall *dbndret = chkp_retbnd_call_by_val (dresult);
134638fd1498Szrj 	      gcall *ibndret = chkp_retbnd_call_by_val (iresult);
134738fd1498Szrj 	      struct cgraph_edge *iedge
134838fd1498Szrj 		= e2->caller->cgraph_node::get_edge (ibndret);
134938fd1498Szrj 
135038fd1498Szrj 	      if (dbndret)
135138fd1498Szrj 		iedge->caller->create_edge (iedge->callee, dbndret, e->count);
135238fd1498Szrj 	    }
135338fd1498Szrj 
135438fd1498Szrj 	  e2->speculative = false;
135538fd1498Szrj 	  e2->count = gimple_bb (e2->call_stmt)->count;
135638fd1498Szrj 	  ref->speculative = false;
135738fd1498Szrj 	  ref->stmt = NULL;
135838fd1498Szrj 	  /* Indirect edges are not both in the call site hash.
135938fd1498Szrj 	     get it updated.  */
136038fd1498Szrj 	  if (e->caller->call_site_hash)
136138fd1498Szrj 	    cgraph_update_edge_in_call_site_hash (e2);
136238fd1498Szrj 	  pop_cfun ();
136338fd1498Szrj 	  /* Continue redirecting E to proper target.  */
136438fd1498Szrj 	}
136538fd1498Szrj     }
136638fd1498Szrj 
136738fd1498Szrj   /* We might propagate instrumented function pointer into
136838fd1498Szrj      not instrumented function and vice versa.  In such a
136938fd1498Szrj      case we need to either fix function declaration or
137038fd1498Szrj      remove bounds from call statement.  */
137138fd1498Szrj   if (flag_check_pointer_bounds && e->callee)
137238fd1498Szrj     skip_bounds = chkp_redirect_edge (e);
137338fd1498Szrj 
137438fd1498Szrj   if (e->indirect_unknown_callee
137538fd1498Szrj       || (decl == e->callee->decl
137638fd1498Szrj 	  && !skip_bounds))
137738fd1498Szrj     return e->call_stmt;
137838fd1498Szrj 
137938fd1498Szrj   if (flag_checking && decl)
138038fd1498Szrj     {
138138fd1498Szrj       cgraph_node *node = cgraph_node::get (decl);
138238fd1498Szrj       gcc_assert (!node || !node->clone.combined_args_to_skip);
138338fd1498Szrj     }
138438fd1498Szrj 
138538fd1498Szrj   if (symtab->dump_file)
138638fd1498Szrj     {
138738fd1498Szrj       fprintf (symtab->dump_file, "updating call of %s -> %s: ",
138838fd1498Szrj 	       e->caller->dump_name (), e->callee->dump_name ());
138938fd1498Szrj       print_gimple_stmt (symtab->dump_file, e->call_stmt, 0, dump_flags);
139038fd1498Szrj       if (e->callee->clone.combined_args_to_skip)
139138fd1498Szrj 	{
139238fd1498Szrj 	  fprintf (symtab->dump_file, " combined args to skip: ");
139338fd1498Szrj 	  dump_bitmap (symtab->dump_file,
139438fd1498Szrj 		       e->callee->clone.combined_args_to_skip);
139538fd1498Szrj 	}
139638fd1498Szrj     }
139738fd1498Szrj 
139838fd1498Szrj   if (e->callee->clone.combined_args_to_skip
139938fd1498Szrj       || skip_bounds)
140038fd1498Szrj     {
140138fd1498Szrj       int lp_nr;
140238fd1498Szrj 
140338fd1498Szrj       new_stmt = e->call_stmt;
140438fd1498Szrj       if (e->callee->clone.combined_args_to_skip)
140538fd1498Szrj 	new_stmt
140638fd1498Szrj 	  = gimple_call_copy_skip_args (new_stmt,
140738fd1498Szrj 					e->callee->clone.combined_args_to_skip);
140838fd1498Szrj       if (skip_bounds)
140938fd1498Szrj 	new_stmt = chkp_copy_call_skip_bounds (new_stmt);
141038fd1498Szrj 
141138fd1498Szrj       tree old_fntype = gimple_call_fntype (e->call_stmt);
141238fd1498Szrj       gimple_call_set_fndecl (new_stmt, e->callee->decl);
141338fd1498Szrj       cgraph_node *origin = e->callee;
141438fd1498Szrj       while (origin->clone_of)
141538fd1498Szrj 	origin = origin->clone_of;
141638fd1498Szrj 
141738fd1498Szrj       if ((origin->former_clone_of
141838fd1498Szrj 	   && old_fntype == TREE_TYPE (origin->former_clone_of))
141938fd1498Szrj 	  || old_fntype == TREE_TYPE (origin->decl))
142038fd1498Szrj 	gimple_call_set_fntype (new_stmt, TREE_TYPE (e->callee->decl));
142138fd1498Szrj       else
142238fd1498Szrj 	{
142338fd1498Szrj 	  bitmap skip = e->callee->clone.combined_args_to_skip;
142438fd1498Szrj 	  tree t = cgraph_build_function_type_skip_args (old_fntype, skip,
142538fd1498Szrj 							 false);
142638fd1498Szrj 	  gimple_call_set_fntype (new_stmt, t);
142738fd1498Szrj 	}
142838fd1498Szrj 
142938fd1498Szrj       if (gimple_vdef (new_stmt)
143038fd1498Szrj 	  && TREE_CODE (gimple_vdef (new_stmt)) == SSA_NAME)
143138fd1498Szrj 	SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt;
143238fd1498Szrj 
143338fd1498Szrj       gsi = gsi_for_stmt (e->call_stmt);
143438fd1498Szrj 
143538fd1498Szrj       /* For optimized away parameters, add on the caller side
143638fd1498Szrj 	 before the call
143738fd1498Szrj 	 DEBUG D#X => parm_Y(D)
143838fd1498Szrj 	 stmts and associate D#X with parm in decl_debug_args_lookup
143938fd1498Szrj 	 vector to say for debug info that if parameter parm had been passed,
144038fd1498Szrj 	 it would have value parm_Y(D).  */
144138fd1498Szrj       if (e->callee->clone.combined_args_to_skip && MAY_HAVE_DEBUG_BIND_STMTS)
144238fd1498Szrj 	{
144338fd1498Szrj 	  vec<tree, va_gc> **debug_args
144438fd1498Szrj 	    = decl_debug_args_lookup (e->callee->decl);
144538fd1498Szrj 	  tree old_decl = gimple_call_fndecl (e->call_stmt);
144638fd1498Szrj 	  if (debug_args && old_decl)
144738fd1498Szrj 	    {
144838fd1498Szrj 	      tree parm;
144938fd1498Szrj 	      unsigned i = 0, num;
145038fd1498Szrj 	      unsigned len = vec_safe_length (*debug_args);
145138fd1498Szrj 	      unsigned nargs = gimple_call_num_args (e->call_stmt);
145238fd1498Szrj 	      for (parm = DECL_ARGUMENTS (old_decl), num = 0;
145338fd1498Szrj 		   parm && num < nargs;
145438fd1498Szrj 		   parm = DECL_CHAIN (parm), num++)
145538fd1498Szrj 		if (bitmap_bit_p (e->callee->clone.combined_args_to_skip, num)
145638fd1498Szrj 		    && is_gimple_reg (parm))
145738fd1498Szrj 		  {
145838fd1498Szrj 		    unsigned last = i;
145938fd1498Szrj 
146038fd1498Szrj 		    while (i < len && (**debug_args)[i] != DECL_ORIGIN (parm))
146138fd1498Szrj 		      i += 2;
146238fd1498Szrj 		    if (i >= len)
146338fd1498Szrj 		      {
146438fd1498Szrj 			i = 0;
146538fd1498Szrj 			while (i < last
146638fd1498Szrj 			       && (**debug_args)[i] != DECL_ORIGIN (parm))
146738fd1498Szrj 			  i += 2;
146838fd1498Szrj 			if (i >= last)
146938fd1498Szrj 			  continue;
147038fd1498Szrj 		      }
147138fd1498Szrj 		    tree ddecl = (**debug_args)[i + 1];
147238fd1498Szrj 		    tree arg = gimple_call_arg (e->call_stmt, num);
147338fd1498Szrj 		    if (!useless_type_conversion_p (TREE_TYPE (ddecl),
147438fd1498Szrj 						    TREE_TYPE (arg)))
147538fd1498Szrj 		      {
147638fd1498Szrj 			tree rhs1;
147738fd1498Szrj 			if (!fold_convertible_p (TREE_TYPE (ddecl), arg))
147838fd1498Szrj 			  continue;
147938fd1498Szrj 			if (TREE_CODE (arg) == SSA_NAME
148038fd1498Szrj 			    && gimple_assign_cast_p (SSA_NAME_DEF_STMT (arg))
148138fd1498Szrj 			    && (rhs1
148238fd1498Szrj 				= gimple_assign_rhs1 (SSA_NAME_DEF_STMT (arg)))
148338fd1498Szrj 			    && useless_type_conversion_p (TREE_TYPE (ddecl),
148438fd1498Szrj 							  TREE_TYPE (rhs1)))
148538fd1498Szrj 			  arg = rhs1;
148638fd1498Szrj 			else
148738fd1498Szrj 			  arg = fold_convert (TREE_TYPE (ddecl), arg);
148838fd1498Szrj 		      }
148938fd1498Szrj 
149038fd1498Szrj 		    gimple *def_temp
149138fd1498Szrj 		      = gimple_build_debug_bind (ddecl, unshare_expr (arg),
149238fd1498Szrj 						 e->call_stmt);
149338fd1498Szrj 		    gsi_insert_before (&gsi, def_temp, GSI_SAME_STMT);
149438fd1498Szrj 		  }
149538fd1498Szrj 	    }
149638fd1498Szrj 	}
149738fd1498Szrj 
149838fd1498Szrj       gsi_replace (&gsi, new_stmt, false);
149938fd1498Szrj       /* We need to defer cleaning EH info on the new statement to
150038fd1498Szrj          fixup-cfg.  We may not have dominator information at this point
150138fd1498Szrj 	 and thus would end up with unreachable blocks and have no way
150238fd1498Szrj 	 to communicate that we need to run CFG cleanup then.  */
150338fd1498Szrj       lp_nr = lookup_stmt_eh_lp (e->call_stmt);
150438fd1498Szrj       if (lp_nr != 0)
150538fd1498Szrj 	{
150638fd1498Szrj 	  remove_stmt_from_eh_lp (e->call_stmt);
150738fd1498Szrj 	  add_stmt_to_eh_lp (new_stmt, lp_nr);
150838fd1498Szrj 	}
150938fd1498Szrj     }
151038fd1498Szrj   else
151138fd1498Szrj     {
151238fd1498Szrj       new_stmt = e->call_stmt;
151338fd1498Szrj       gimple_call_set_fndecl (new_stmt, e->callee->decl);
151438fd1498Szrj       update_stmt_fn (DECL_STRUCT_FUNCTION (e->caller->decl), new_stmt);
151538fd1498Szrj     }
151638fd1498Szrj 
151738fd1498Szrj   /* If changing the call to __cxa_pure_virtual or similar noreturn function,
151838fd1498Szrj      adjust gimple_call_fntype too.  */
151938fd1498Szrj   if (gimple_call_noreturn_p (new_stmt)
152038fd1498Szrj       && VOID_TYPE_P (TREE_TYPE (TREE_TYPE (e->callee->decl)))
152138fd1498Szrj       && TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl))
152238fd1498Szrj       && (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl)))
152338fd1498Szrj 	  == void_type_node))
152438fd1498Szrj     gimple_call_set_fntype (new_stmt, TREE_TYPE (e->callee->decl));
152538fd1498Szrj 
152638fd1498Szrj   /* If the call becomes noreturn, remove the LHS if possible.  */
152738fd1498Szrj   tree lhs = gimple_call_lhs (new_stmt);
152838fd1498Szrj   if (lhs
152938fd1498Szrj       && gimple_call_noreturn_p (new_stmt)
153038fd1498Szrj       && (VOID_TYPE_P (TREE_TYPE (gimple_call_fntype (new_stmt)))
153138fd1498Szrj 	  || should_remove_lhs_p (lhs)))
153238fd1498Szrj     {
153338fd1498Szrj       if (TREE_CODE (lhs) == SSA_NAME)
153438fd1498Szrj 	{
153538fd1498Szrj 	  tree var = create_tmp_reg_fn (DECL_STRUCT_FUNCTION (e->caller->decl),
153638fd1498Szrj 					TREE_TYPE (lhs), NULL);
153738fd1498Szrj 	  var = get_or_create_ssa_default_def
153838fd1498Szrj 		  (DECL_STRUCT_FUNCTION (e->caller->decl), var);
153938fd1498Szrj 	  gimple *set_stmt = gimple_build_assign (lhs, var);
154038fd1498Szrj           gsi = gsi_for_stmt (new_stmt);
154138fd1498Szrj 	  gsi_insert_before_without_update (&gsi, set_stmt, GSI_SAME_STMT);
154238fd1498Szrj 	  update_stmt_fn (DECL_STRUCT_FUNCTION (e->caller->decl), set_stmt);
154338fd1498Szrj 	}
154438fd1498Szrj       gimple_call_set_lhs (new_stmt, NULL_TREE);
154538fd1498Szrj       update_stmt_fn (DECL_STRUCT_FUNCTION (e->caller->decl), new_stmt);
154638fd1498Szrj     }
154738fd1498Szrj 
154838fd1498Szrj   /* If new callee has no static chain, remove it.  */
154938fd1498Szrj   if (gimple_call_chain (new_stmt) && !DECL_STATIC_CHAIN (e->callee->decl))
155038fd1498Szrj     {
155138fd1498Szrj       gimple_call_set_chain (new_stmt, NULL);
155238fd1498Szrj       update_stmt_fn (DECL_STRUCT_FUNCTION (e->caller->decl), new_stmt);
155338fd1498Szrj     }
155438fd1498Szrj 
155538fd1498Szrj   maybe_remove_unused_call_args (DECL_STRUCT_FUNCTION (e->caller->decl),
155638fd1498Szrj 				 new_stmt);
155738fd1498Szrj 
155838fd1498Szrj   e->caller->set_call_stmt_including_clones (e->call_stmt, new_stmt, false);
155938fd1498Szrj 
156038fd1498Szrj   if (symtab->dump_file)
156138fd1498Szrj     {
156238fd1498Szrj       fprintf (symtab->dump_file, "  updated to:");
156338fd1498Szrj       print_gimple_stmt (symtab->dump_file, e->call_stmt, 0, dump_flags);
156438fd1498Szrj     }
156538fd1498Szrj   return new_stmt;
156638fd1498Szrj }
156738fd1498Szrj 
156838fd1498Szrj /* Update or remove the corresponding cgraph edge if a GIMPLE_CALL
156938fd1498Szrj    OLD_STMT changed into NEW_STMT.  OLD_CALL is gimple_call_fndecl
157038fd1498Szrj    of OLD_STMT if it was previously call statement.
157138fd1498Szrj    If NEW_STMT is NULL, the call has been dropped without any
157238fd1498Szrj    replacement.  */
157338fd1498Szrj 
157438fd1498Szrj static void
cgraph_update_edges_for_call_stmt_node(cgraph_node * node,gimple * old_stmt,tree old_call,gimple * new_stmt)157538fd1498Szrj cgraph_update_edges_for_call_stmt_node (cgraph_node *node,
157638fd1498Szrj 					gimple *old_stmt, tree old_call,
157738fd1498Szrj 					gimple *new_stmt)
157838fd1498Szrj {
157938fd1498Szrj   tree new_call = (new_stmt && is_gimple_call (new_stmt))
158038fd1498Szrj 		  ? gimple_call_fndecl (new_stmt) : 0;
158138fd1498Szrj 
158238fd1498Szrj   /* We are seeing indirect calls, then there is nothing to update.  */
158338fd1498Szrj   if (!new_call && !old_call)
158438fd1498Szrj     return;
158538fd1498Szrj   /* See if we turned indirect call into direct call or folded call to one builtin
158638fd1498Szrj      into different builtin.  */
158738fd1498Szrj   if (old_call != new_call)
158838fd1498Szrj     {
158938fd1498Szrj       cgraph_edge *e = node->get_edge (old_stmt);
159038fd1498Szrj       cgraph_edge *ne = NULL;
159138fd1498Szrj       profile_count count;
159238fd1498Szrj 
159338fd1498Szrj       if (e)
159438fd1498Szrj 	{
159538fd1498Szrj 	  /* Keep calls marked as dead dead.  */
159638fd1498Szrj 	  if (new_stmt && is_gimple_call (new_stmt) && e->callee
159738fd1498Szrj 	      && DECL_BUILT_IN_CLASS (e->callee->decl) == BUILT_IN_NORMAL
159838fd1498Szrj 	      && DECL_FUNCTION_CODE (e->callee->decl) == BUILT_IN_UNREACHABLE)
159938fd1498Szrj 	    {
160038fd1498Szrj               node->get_edge (old_stmt)->set_call_stmt
160138fd1498Szrj 		 (as_a <gcall *> (new_stmt));
160238fd1498Szrj 	      return;
160338fd1498Szrj 	    }
160438fd1498Szrj 	  /* See if the edge is already there and has the correct callee.  It
160538fd1498Szrj 	     might be so because of indirect inlining has already updated
160638fd1498Szrj 	     it.  We also might've cloned and redirected the edge.  */
160738fd1498Szrj 	  if (new_call && e->callee)
160838fd1498Szrj 	    {
160938fd1498Szrj 	      cgraph_node *callee = e->callee;
161038fd1498Szrj 	      while (callee)
161138fd1498Szrj 		{
161238fd1498Szrj 		  if (callee->decl == new_call
161338fd1498Szrj 		      || callee->former_clone_of == new_call)
161438fd1498Szrj 		    {
161538fd1498Szrj 		      e->set_call_stmt (as_a <gcall *> (new_stmt));
161638fd1498Szrj 		      return;
161738fd1498Szrj 		    }
161838fd1498Szrj 		  callee = callee->clone_of;
161938fd1498Szrj 		}
162038fd1498Szrj 	    }
162138fd1498Szrj 
162238fd1498Szrj 	  /* Otherwise remove edge and create new one; we can't simply redirect
162338fd1498Szrj 	     since function has changed, so inline plan and other information
162438fd1498Szrj 	     attached to edge is invalid.  */
162538fd1498Szrj 	  count = e->count;
162638fd1498Szrj  	  if (e->indirect_unknown_callee || e->inline_failed)
162738fd1498Szrj 	    e->remove ();
162838fd1498Szrj 	  else
162938fd1498Szrj 	    e->callee->remove_symbol_and_inline_clones ();
163038fd1498Szrj 	}
163138fd1498Szrj       else if (new_call)
163238fd1498Szrj 	{
163338fd1498Szrj 	  /* We are seeing new direct call; compute profile info based on BB.  */
163438fd1498Szrj 	  basic_block bb = gimple_bb (new_stmt);
163538fd1498Szrj 	  count = bb->count;
163638fd1498Szrj 	}
163738fd1498Szrj 
163838fd1498Szrj       if (new_call)
163938fd1498Szrj 	{
164038fd1498Szrj 	  ne = node->create_edge (cgraph_node::get_create (new_call),
164138fd1498Szrj 				  as_a <gcall *> (new_stmt), count);
164238fd1498Szrj 	  gcc_assert (ne->inline_failed);
164338fd1498Szrj 	}
164438fd1498Szrj     }
164538fd1498Szrj   /* We only updated the call stmt; update pointer in cgraph edge..  */
164638fd1498Szrj   else if (old_stmt != new_stmt)
164738fd1498Szrj     node->get_edge (old_stmt)->set_call_stmt (as_a <gcall *> (new_stmt));
164838fd1498Szrj }
164938fd1498Szrj 
165038fd1498Szrj /* Update or remove the corresponding cgraph edge if a GIMPLE_CALL
165138fd1498Szrj    OLD_STMT changed into NEW_STMT.  OLD_DECL is gimple_call_fndecl
165238fd1498Szrj    of OLD_STMT before it was updated (updating can happen inplace).  */
165338fd1498Szrj 
165438fd1498Szrj void
cgraph_update_edges_for_call_stmt(gimple * old_stmt,tree old_decl,gimple * new_stmt)165538fd1498Szrj cgraph_update_edges_for_call_stmt (gimple *old_stmt, tree old_decl,
165638fd1498Szrj 				   gimple *new_stmt)
165738fd1498Szrj {
165838fd1498Szrj   cgraph_node *orig = cgraph_node::get (cfun->decl);
165938fd1498Szrj   cgraph_node *node;
166038fd1498Szrj 
166138fd1498Szrj   gcc_checking_assert (orig);
166238fd1498Szrj   cgraph_update_edges_for_call_stmt_node (orig, old_stmt, old_decl, new_stmt);
166338fd1498Szrj   if (orig->clones)
166438fd1498Szrj     for (node = orig->clones; node != orig;)
166538fd1498Szrj       {
166638fd1498Szrj         cgraph_update_edges_for_call_stmt_node (node, old_stmt, old_decl, new_stmt);
166738fd1498Szrj 	if (node->clones)
166838fd1498Szrj 	  node = node->clones;
166938fd1498Szrj 	else if (node->next_sibling_clone)
167038fd1498Szrj 	  node = node->next_sibling_clone;
167138fd1498Szrj 	else
167238fd1498Szrj 	  {
167338fd1498Szrj 	    while (node != orig && !node->next_sibling_clone)
167438fd1498Szrj 	      node = node->clone_of;
167538fd1498Szrj 	    if (node != orig)
167638fd1498Szrj 	      node = node->next_sibling_clone;
167738fd1498Szrj 	  }
167838fd1498Szrj       }
167938fd1498Szrj }
168038fd1498Szrj 
168138fd1498Szrj 
168238fd1498Szrj /* Remove all callees from the node.  */
168338fd1498Szrj 
168438fd1498Szrj void
remove_callees(void)168538fd1498Szrj cgraph_node::remove_callees (void)
168638fd1498Szrj {
168738fd1498Szrj   cgraph_edge *e, *f;
168838fd1498Szrj 
168938fd1498Szrj   /* It is sufficient to remove the edges from the lists of callers of
169038fd1498Szrj      the callees.  The callee list of the node can be zapped with one
169138fd1498Szrj      assignment.  */
169238fd1498Szrj   for (e = callees; e; e = f)
169338fd1498Szrj     {
169438fd1498Szrj       f = e->next_callee;
169538fd1498Szrj       symtab->call_edge_removal_hooks (e);
169638fd1498Szrj       if (!e->indirect_unknown_callee)
169738fd1498Szrj 	e->remove_callee ();
169838fd1498Szrj       symtab->free_edge (e);
169938fd1498Szrj     }
170038fd1498Szrj   for (e = indirect_calls; e; e = f)
170138fd1498Szrj     {
170238fd1498Szrj       f = e->next_callee;
170338fd1498Szrj       symtab->call_edge_removal_hooks (e);
170438fd1498Szrj       if (!e->indirect_unknown_callee)
170538fd1498Szrj 	e->remove_callee ();
170638fd1498Szrj       symtab->free_edge (e);
170738fd1498Szrj     }
170838fd1498Szrj   indirect_calls = NULL;
170938fd1498Szrj   callees = NULL;
171038fd1498Szrj   if (call_site_hash)
171138fd1498Szrj     {
171238fd1498Szrj       call_site_hash->empty ();
171338fd1498Szrj       call_site_hash = NULL;
171438fd1498Szrj     }
171538fd1498Szrj }
171638fd1498Szrj 
171738fd1498Szrj /* Remove all callers from the node.  */
171838fd1498Szrj 
171938fd1498Szrj void
remove_callers(void)172038fd1498Szrj cgraph_node::remove_callers (void)
172138fd1498Szrj {
172238fd1498Szrj   cgraph_edge *e, *f;
172338fd1498Szrj 
172438fd1498Szrj   /* It is sufficient to remove the edges from the lists of callees of
172538fd1498Szrj      the callers.  The caller list of the node can be zapped with one
172638fd1498Szrj      assignment.  */
172738fd1498Szrj   for (e = callers; e; e = f)
172838fd1498Szrj     {
172938fd1498Szrj       f = e->next_caller;
173038fd1498Szrj       symtab->call_edge_removal_hooks (e);
173138fd1498Szrj       e->remove_caller ();
173238fd1498Szrj       symtab->free_edge (e);
173338fd1498Szrj     }
173438fd1498Szrj   callers = NULL;
173538fd1498Szrj }
173638fd1498Szrj 
173738fd1498Szrj /* Helper function for cgraph_release_function_body and free_lang_data.
173838fd1498Szrj    It releases body from function DECL without having to inspect its
173938fd1498Szrj    possibly non-existent symtab node.  */
174038fd1498Szrj 
174138fd1498Szrj void
release_function_body(tree decl)174238fd1498Szrj release_function_body (tree decl)
174338fd1498Szrj {
174438fd1498Szrj   function *fn = DECL_STRUCT_FUNCTION (decl);
174538fd1498Szrj   if (fn)
174638fd1498Szrj     {
174738fd1498Szrj       if (fn->cfg
174838fd1498Szrj 	  && loops_for_fn (fn))
174938fd1498Szrj 	{
175038fd1498Szrj 	  fn->curr_properties &= ~PROP_loops;
175138fd1498Szrj 	  loop_optimizer_finalize (fn);
175238fd1498Szrj 	}
175338fd1498Szrj       if (fn->gimple_df)
175438fd1498Szrj 	{
175538fd1498Szrj 	  delete_tree_ssa (fn);
175638fd1498Szrj 	  fn->eh = NULL;
175738fd1498Szrj 	}
175838fd1498Szrj       if (fn->cfg)
175938fd1498Szrj 	{
176038fd1498Szrj 	  gcc_assert (!dom_info_available_p (fn, CDI_DOMINATORS));
176138fd1498Szrj 	  gcc_assert (!dom_info_available_p (fn, CDI_POST_DOMINATORS));
176238fd1498Szrj 	  delete_tree_cfg_annotations (fn);
176338fd1498Szrj 	  clear_edges (fn);
176438fd1498Szrj 	  fn->cfg = NULL;
176538fd1498Szrj 	}
176638fd1498Szrj       if (fn->value_histograms)
176738fd1498Szrj 	free_histograms (fn);
176838fd1498Szrj       gimple_set_body (decl, NULL);
176938fd1498Szrj       /* Struct function hangs a lot of data that would leak if we didn't
177038fd1498Szrj          removed all pointers to it.   */
177138fd1498Szrj       ggc_free (fn);
177238fd1498Szrj       DECL_STRUCT_FUNCTION (decl) = NULL;
177338fd1498Szrj     }
177438fd1498Szrj   DECL_SAVED_TREE (decl) = NULL;
177538fd1498Szrj }
177638fd1498Szrj 
177738fd1498Szrj /* Release memory used to represent body of function.
177838fd1498Szrj    Use this only for functions that are released before being translated to
177938fd1498Szrj    target code (i.e. RTL).  Functions that are compiled to RTL and beyond
178038fd1498Szrj    are free'd in final.c via free_after_compilation().
178138fd1498Szrj    KEEP_ARGUMENTS are useful only if you want to rebuild body as thunk.  */
178238fd1498Szrj 
178338fd1498Szrj void
release_body(bool keep_arguments)178438fd1498Szrj cgraph_node::release_body (bool keep_arguments)
178538fd1498Szrj {
178638fd1498Szrj   ipa_transforms_to_apply.release ();
178738fd1498Szrj   if (!used_as_abstract_origin && symtab->state != PARSING)
178838fd1498Szrj     {
178938fd1498Szrj       DECL_RESULT (decl) = NULL;
179038fd1498Szrj 
179138fd1498Szrj       if (!keep_arguments)
179238fd1498Szrj 	DECL_ARGUMENTS (decl) = NULL;
179338fd1498Szrj     }
179438fd1498Szrj   /* If the node is abstract and needed, then do not clear
179538fd1498Szrj      DECL_INITIAL of its associated function declaration because it's
179638fd1498Szrj      needed to emit debug info later.  */
179738fd1498Szrj   if (!used_as_abstract_origin && DECL_INITIAL (decl))
179838fd1498Szrj     DECL_INITIAL (decl) = error_mark_node;
179938fd1498Szrj   release_function_body (decl);
180038fd1498Szrj   if (lto_file_data)
180138fd1498Szrj     {
180238fd1498Szrj       lto_free_function_in_decl_state_for_node (this);
180338fd1498Szrj       lto_file_data = NULL;
180438fd1498Szrj     }
180538fd1498Szrj }
180638fd1498Szrj 
180738fd1498Szrj /* Remove function from symbol table.  */
180838fd1498Szrj 
180938fd1498Szrj void
remove(void)181038fd1498Szrj cgraph_node::remove (void)
181138fd1498Szrj {
181238fd1498Szrj   cgraph_node *n;
181338fd1498Szrj   int uid = this->uid;
181438fd1498Szrj 
181538fd1498Szrj   if (symtab->ipa_clones_dump_file && symtab->cloned_nodes.contains (this))
181638fd1498Szrj     fprintf (symtab->ipa_clones_dump_file,
181738fd1498Szrj 	     "Callgraph removal;%s;%d;%s;%d;%d\n", asm_name (), order,
181838fd1498Szrj 	     DECL_SOURCE_FILE (decl), DECL_SOURCE_LINE (decl),
181938fd1498Szrj 	     DECL_SOURCE_COLUMN (decl));
182038fd1498Szrj 
182138fd1498Szrj   symtab->call_cgraph_removal_hooks (this);
182238fd1498Szrj   remove_callers ();
182338fd1498Szrj   remove_callees ();
182438fd1498Szrj   ipa_transforms_to_apply.release ();
182538fd1498Szrj   delete_function_version (function_version ());
182638fd1498Szrj 
182738fd1498Szrj   /* Incremental inlining access removed nodes stored in the postorder list.
182838fd1498Szrj      */
182938fd1498Szrj   force_output = false;
183038fd1498Szrj   forced_by_abi = false;
183138fd1498Szrj   for (n = nested; n; n = n->next_nested)
183238fd1498Szrj     n->origin = NULL;
183338fd1498Szrj   nested = NULL;
183438fd1498Szrj   if (origin)
183538fd1498Szrj     {
183638fd1498Szrj       cgraph_node **node2 = &origin->nested;
183738fd1498Szrj 
183838fd1498Szrj       while (*node2 != this)
183938fd1498Szrj 	node2 = &(*node2)->next_nested;
184038fd1498Szrj       *node2 = next_nested;
184138fd1498Szrj     }
184238fd1498Szrj   unregister ();
184338fd1498Szrj   if (prev_sibling_clone)
184438fd1498Szrj     prev_sibling_clone->next_sibling_clone = next_sibling_clone;
184538fd1498Szrj   else if (clone_of)
184638fd1498Szrj     clone_of->clones = next_sibling_clone;
184738fd1498Szrj   if (next_sibling_clone)
184838fd1498Szrj     next_sibling_clone->prev_sibling_clone = prev_sibling_clone;
184938fd1498Szrj   if (clones)
185038fd1498Szrj     {
185138fd1498Szrj       cgraph_node *n, *next;
185238fd1498Szrj 
185338fd1498Szrj       if (clone_of)
185438fd1498Szrj         {
185538fd1498Szrj 	  for (n = clones; n->next_sibling_clone; n = n->next_sibling_clone)
185638fd1498Szrj 	    n->clone_of = clone_of;
185738fd1498Szrj 	  n->clone_of = clone_of;
185838fd1498Szrj 	  n->next_sibling_clone = clone_of->clones;
185938fd1498Szrj 	  if (clone_of->clones)
186038fd1498Szrj 	    clone_of->clones->prev_sibling_clone = n;
186138fd1498Szrj 	  clone_of->clones = clones;
186238fd1498Szrj 	}
186338fd1498Szrj       else
186438fd1498Szrj         {
186538fd1498Szrj 	  /* We are removing node with clones.  This makes clones inconsistent,
186638fd1498Szrj 	     but assume they will be removed subsequently and just keep clone
186738fd1498Szrj 	     tree intact.  This can happen in unreachable function removal since
186838fd1498Szrj 	     we remove unreachable functions in random order, not by bottom-up
186938fd1498Szrj 	     walk of clone trees.  */
187038fd1498Szrj 	  for (n = clones; n; n = next)
187138fd1498Szrj 	    {
187238fd1498Szrj 	       next = n->next_sibling_clone;
187338fd1498Szrj 	       n->next_sibling_clone = NULL;
187438fd1498Szrj 	       n->prev_sibling_clone = NULL;
187538fd1498Szrj 	       n->clone_of = NULL;
187638fd1498Szrj 	    }
187738fd1498Szrj 	}
187838fd1498Szrj     }
187938fd1498Szrj 
188038fd1498Szrj   /* While all the clones are removed after being proceeded, the function
188138fd1498Szrj      itself is kept in the cgraph even after it is compiled.  Check whether
188238fd1498Szrj      we are done with this body and reclaim it proactively if this is the case.
188338fd1498Szrj      */
188438fd1498Szrj   if (symtab->state != LTO_STREAMING)
188538fd1498Szrj     {
188638fd1498Szrj       n = cgraph_node::get (decl);
188738fd1498Szrj       if (!n
188838fd1498Szrj 	  || (!n->clones && !n->clone_of && !n->global.inlined_to
188938fd1498Szrj 	      && ((symtab->global_info_ready || in_lto_p)
189038fd1498Szrj 		  && (TREE_ASM_WRITTEN (n->decl)
189138fd1498Szrj 		      || DECL_EXTERNAL (n->decl)
189238fd1498Szrj 		      || !n->analyzed
189338fd1498Szrj 		      || (!flag_wpa && n->in_other_partition)))))
189438fd1498Szrj 	release_body ();
189538fd1498Szrj     }
189638fd1498Szrj   else
189738fd1498Szrj     {
189838fd1498Szrj       lto_free_function_in_decl_state_for_node (this);
189938fd1498Szrj       lto_file_data = NULL;
190038fd1498Szrj     }
190138fd1498Szrj 
190238fd1498Szrj   decl = NULL;
190338fd1498Szrj   if (call_site_hash)
190438fd1498Szrj     {
190538fd1498Szrj       call_site_hash->empty ();
190638fd1498Szrj       call_site_hash = NULL;
190738fd1498Szrj     }
190838fd1498Szrj 
190938fd1498Szrj   if (instrumented_version)
191038fd1498Szrj     {
191138fd1498Szrj       instrumented_version->instrumented_version = NULL;
191238fd1498Szrj       instrumented_version = NULL;
191338fd1498Szrj     }
191438fd1498Szrj 
191538fd1498Szrj   symtab->release_symbol (this, uid);
191638fd1498Szrj }
191738fd1498Szrj 
191838fd1498Szrj /* Likewise indicate that a node is having address taken.  */
191938fd1498Szrj 
192038fd1498Szrj void
mark_address_taken(void)192138fd1498Szrj cgraph_node::mark_address_taken (void)
192238fd1498Szrj {
192338fd1498Szrj   /* Indirect inlining can figure out that all uses of the address are
192438fd1498Szrj      inlined.  */
192538fd1498Szrj   if (global.inlined_to)
192638fd1498Szrj     {
192738fd1498Szrj       gcc_assert (cfun->after_inlining);
192838fd1498Szrj       gcc_assert (callers->indirect_inlining_edge);
192938fd1498Szrj       return;
193038fd1498Szrj     }
193138fd1498Szrj   /* FIXME: address_taken flag is used both as a shortcut for testing whether
193238fd1498Szrj      IPA_REF_ADDR reference exists (and thus it should be set on node
193338fd1498Szrj      representing alias we take address of) and as a test whether address
193438fd1498Szrj      of the object was taken (and thus it should be set on node alias is
193538fd1498Szrj      referring to).  We should remove the first use and the remove the
193638fd1498Szrj      following set.  */
193738fd1498Szrj   address_taken = 1;
193838fd1498Szrj   cgraph_node *node = ultimate_alias_target ();
193938fd1498Szrj   node->address_taken = 1;
194038fd1498Szrj }
194138fd1498Szrj 
194238fd1498Szrj /* Return local info for the compiled function.  */
194338fd1498Szrj 
194438fd1498Szrj cgraph_local_info *
local_info(tree decl)194538fd1498Szrj cgraph_node::local_info (tree decl)
194638fd1498Szrj {
194738fd1498Szrj   gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
194838fd1498Szrj   cgraph_node *node = get (decl);
194938fd1498Szrj   if (!node)
195038fd1498Szrj     return NULL;
195138fd1498Szrj   return &node->ultimate_alias_target ()->local;
195238fd1498Szrj }
195338fd1498Szrj 
195438fd1498Szrj /* Return local info for the compiled function.  */
195538fd1498Szrj 
195638fd1498Szrj cgraph_rtl_info *
rtl_info(tree decl)195738fd1498Szrj cgraph_node::rtl_info (tree decl)
195838fd1498Szrj {
195938fd1498Szrj   gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
196038fd1498Szrj   cgraph_node *node = get (decl);
196138fd1498Szrj   if (!node)
196238fd1498Szrj     return NULL;
196338fd1498Szrj   enum availability avail;
196438fd1498Szrj   node = node->ultimate_alias_target (&avail);
196538fd1498Szrj   if (decl != current_function_decl
196638fd1498Szrj       && (avail < AVAIL_AVAILABLE
196738fd1498Szrj 	  || (node->decl != current_function_decl
196838fd1498Szrj 	      && !TREE_ASM_WRITTEN (node->decl))))
196938fd1498Szrj     return NULL;
197038fd1498Szrj   /* Allocate if it doesn't exist.  */
197138fd1498Szrj   if (node->rtl == NULL)
197238fd1498Szrj     node->rtl = ggc_cleared_alloc<cgraph_rtl_info> ();
197338fd1498Szrj   return node->rtl;
197438fd1498Szrj }
197538fd1498Szrj 
197638fd1498Szrj /* Return a string describing the failure REASON.  */
197738fd1498Szrj 
197838fd1498Szrj const char*
cgraph_inline_failed_string(cgraph_inline_failed_t reason)197938fd1498Szrj cgraph_inline_failed_string (cgraph_inline_failed_t reason)
198038fd1498Szrj {
198138fd1498Szrj #undef DEFCIFCODE
198238fd1498Szrj #define DEFCIFCODE(code, type, string)	string,
198338fd1498Szrj 
198438fd1498Szrj   static const char *cif_string_table[CIF_N_REASONS] = {
198538fd1498Szrj #include "cif-code.def"
198638fd1498Szrj   };
198738fd1498Szrj 
198838fd1498Szrj   /* Signedness of an enum type is implementation defined, so cast it
198938fd1498Szrj      to unsigned before testing. */
199038fd1498Szrj   gcc_assert ((unsigned) reason < CIF_N_REASONS);
199138fd1498Szrj   return cif_string_table[reason];
199238fd1498Szrj }
199338fd1498Szrj 
199438fd1498Szrj /* Return a type describing the failure REASON.  */
199538fd1498Szrj 
199638fd1498Szrj cgraph_inline_failed_type_t
cgraph_inline_failed_type(cgraph_inline_failed_t reason)199738fd1498Szrj cgraph_inline_failed_type (cgraph_inline_failed_t reason)
199838fd1498Szrj {
199938fd1498Szrj #undef DEFCIFCODE
200038fd1498Szrj #define DEFCIFCODE(code, type, string)	type,
200138fd1498Szrj 
200238fd1498Szrj   static cgraph_inline_failed_type_t cif_type_table[CIF_N_REASONS] = {
200338fd1498Szrj #include "cif-code.def"
200438fd1498Szrj   };
200538fd1498Szrj 
200638fd1498Szrj   /* Signedness of an enum type is implementation defined, so cast it
200738fd1498Szrj      to unsigned before testing. */
200838fd1498Szrj   gcc_assert ((unsigned) reason < CIF_N_REASONS);
200938fd1498Szrj   return cif_type_table[reason];
201038fd1498Szrj }
201138fd1498Szrj 
201238fd1498Szrj /* Names used to print out the availability enum.  */
201338fd1498Szrj const char * const cgraph_availability_names[] =
201438fd1498Szrj   {"unset", "not_available", "overwritable", "available", "local"};
201538fd1498Szrj 
201638fd1498Szrj /* Output flags of edge to a file F.  */
201738fd1498Szrj 
201838fd1498Szrj void
dump_edge_flags(FILE * f)201938fd1498Szrj cgraph_edge::dump_edge_flags (FILE *f)
202038fd1498Szrj {
202138fd1498Szrj   if (speculative)
202238fd1498Szrj     fprintf (f, "(speculative) ");
202338fd1498Szrj   if (!inline_failed)
202438fd1498Szrj     fprintf (f, "(inlined) ");
202538fd1498Szrj   if (call_stmt_cannot_inline_p)
202638fd1498Szrj     fprintf (f, "(call_stmt_cannot_inline_p) ");
202738fd1498Szrj   if (indirect_inlining_edge)
202838fd1498Szrj     fprintf (f, "(indirect_inlining) ");
202938fd1498Szrj   if (count.initialized_p ())
203038fd1498Szrj     {
203138fd1498Szrj       fprintf (f, "(");
203238fd1498Szrj       count.dump (f);
203338fd1498Szrj       fprintf (f, ",");
203438fd1498Szrj       fprintf (f, "%.2f per call) ", sreal_frequency ().to_double ());
203538fd1498Szrj     }
203638fd1498Szrj   if (can_throw_external)
203738fd1498Szrj     fprintf (f, "(can throw external) ");
203838fd1498Szrj }
203938fd1498Szrj 
204038fd1498Szrj /* Dump call graph node to file F.  */
204138fd1498Szrj 
204238fd1498Szrj void
dump(FILE * f)204338fd1498Szrj cgraph_node::dump (FILE *f)
204438fd1498Szrj {
204538fd1498Szrj   cgraph_edge *edge;
204638fd1498Szrj 
204738fd1498Szrj   dump_base (f);
204838fd1498Szrj 
204938fd1498Szrj   if (global.inlined_to)
205038fd1498Szrj     fprintf (f, "  Function %s is inline copy in %s\n",
205138fd1498Szrj 	     dump_name (),
205238fd1498Szrj 	     global.inlined_to->dump_name ());
205338fd1498Szrj   if (clone_of)
205438fd1498Szrj     fprintf (f, "  Clone of %s\n", clone_of->dump_asm_name ());
205538fd1498Szrj   if (symtab->function_flags_ready)
205638fd1498Szrj     fprintf (f, "  Availability: %s\n",
205738fd1498Szrj 	     cgraph_availability_names [get_availability ()]);
205838fd1498Szrj 
205938fd1498Szrj   if (profile_id)
206038fd1498Szrj     fprintf (f, "  Profile id: %i\n",
206138fd1498Szrj 	     profile_id);
206238fd1498Szrj   fprintf (f, "  First run: %i\n", tp_first_run);
206338fd1498Szrj   cgraph_function_version_info *vi = function_version ();
206438fd1498Szrj   if (vi != NULL)
206538fd1498Szrj     {
206638fd1498Szrj       fprintf (f, "  Version info: ");
206738fd1498Szrj       if (vi->prev != NULL)
206838fd1498Szrj 	{
206938fd1498Szrj 	  fprintf (f, "prev: ");
207038fd1498Szrj 	  fprintf (f, "%s ", vi->prev->this_node->dump_asm_name ());
207138fd1498Szrj 	}
207238fd1498Szrj       if (vi->next != NULL)
207338fd1498Szrj 	{
207438fd1498Szrj 	  fprintf (f, "next: ");
207538fd1498Szrj 	  fprintf (f, "%s ", vi->next->this_node->dump_asm_name ());
207638fd1498Szrj 	}
207738fd1498Szrj       if (vi->dispatcher_resolver != NULL_TREE)
207838fd1498Szrj 	fprintf (f, "dispatcher: %s",
207938fd1498Szrj 		 lang_hooks.decl_printable_name (vi->dispatcher_resolver, 2));
208038fd1498Szrj 
208138fd1498Szrj       fprintf (f, "\n");
208238fd1498Szrj     }
208338fd1498Szrj   fprintf (f, "  Function flags:");
208438fd1498Szrj   if (count.initialized_p ())
208538fd1498Szrj     {
208638fd1498Szrj       fprintf (f, " count: ");
208738fd1498Szrj       count.dump (f);
208838fd1498Szrj     }
208938fd1498Szrj   if (origin)
209038fd1498Szrj     fprintf (f, " nested in: %s", origin->asm_name ());
209138fd1498Szrj   if (gimple_has_body_p (decl))
209238fd1498Szrj     fprintf (f, " body");
209338fd1498Szrj   if (process)
209438fd1498Szrj     fprintf (f, " process");
209538fd1498Szrj   if (local.local)
209638fd1498Szrj     fprintf (f, " local");
209738fd1498Szrj   if (local.redefined_extern_inline)
209838fd1498Szrj     fprintf (f, " redefined_extern_inline");
209938fd1498Szrj   if (only_called_at_startup)
210038fd1498Szrj     fprintf (f, " only_called_at_startup");
210138fd1498Szrj   if (only_called_at_exit)
210238fd1498Szrj     fprintf (f, " only_called_at_exit");
210338fd1498Szrj   if (tm_clone)
210438fd1498Szrj     fprintf (f, " tm_clone");
210538fd1498Szrj   if (calls_comdat_local)
210638fd1498Szrj     fprintf (f, " calls_comdat_local");
210738fd1498Szrj   if (icf_merged)
210838fd1498Szrj     fprintf (f, " icf_merged");
210938fd1498Szrj   if (merged_comdat)
211038fd1498Szrj     fprintf (f, " merged_comdat");
211138fd1498Szrj   if (split_part)
211238fd1498Szrj     fprintf (f, " split_part");
211338fd1498Szrj   if (indirect_call_target)
211438fd1498Szrj     fprintf (f, " indirect_call_target");
211538fd1498Szrj   if (nonfreeing_fn)
211638fd1498Szrj     fprintf (f, " nonfreeing_fn");
211738fd1498Szrj   if (DECL_STATIC_CONSTRUCTOR (decl))
211838fd1498Szrj     fprintf (f," static_constructor (priority:%i)", get_init_priority ());
211938fd1498Szrj   if (DECL_STATIC_DESTRUCTOR (decl))
212038fd1498Szrj     fprintf (f," static_destructor (priority:%i)", get_fini_priority ());
212138fd1498Szrj   if (frequency == NODE_FREQUENCY_HOT)
212238fd1498Szrj     fprintf (f, " hot");
212338fd1498Szrj   if (frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED)
212438fd1498Szrj     fprintf (f, " unlikely_executed");
212538fd1498Szrj   if (frequency == NODE_FREQUENCY_EXECUTED_ONCE)
212638fd1498Szrj     fprintf (f, " executed_once");
212738fd1498Szrj   if (only_called_at_startup)
212838fd1498Szrj     fprintf (f, " only_called_at_startup");
212938fd1498Szrj   if (only_called_at_exit)
213038fd1498Szrj     fprintf (f, " only_called_at_exit");
213138fd1498Szrj   if (opt_for_fn (decl, optimize_size))
213238fd1498Szrj     fprintf (f, " optimize_size");
213338fd1498Szrj   if (parallelized_function)
213438fd1498Szrj     fprintf (f, " parallelized_function");
213538fd1498Szrj 
213638fd1498Szrj   fprintf (f, "\n");
213738fd1498Szrj 
213838fd1498Szrj   if (thunk.thunk_p)
213938fd1498Szrj     {
214038fd1498Szrj       fprintf (f, "  Thunk");
214138fd1498Szrj       if (thunk.alias)
214238fd1498Szrj         fprintf (f, "  of %s (asm: %s)",
214338fd1498Szrj 		 lang_hooks.decl_printable_name (thunk.alias, 2),
214438fd1498Szrj 		 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (thunk.alias)));
214538fd1498Szrj       fprintf (f, " fixed offset %i virtual value %i has "
214638fd1498Szrj 	       "virtual offset %i)\n",
214738fd1498Szrj 	       (int)thunk.fixed_offset,
214838fd1498Szrj 	       (int)thunk.virtual_value,
214938fd1498Szrj 	       (int)thunk.virtual_offset_p);
215038fd1498Szrj     }
215138fd1498Szrj   if (alias && thunk.alias
215238fd1498Szrj       && DECL_P (thunk.alias))
215338fd1498Szrj     {
215438fd1498Szrj       fprintf (f, "  Alias of %s",
215538fd1498Szrj 	       lang_hooks.decl_printable_name (thunk.alias, 2));
215638fd1498Szrj       if (DECL_ASSEMBLER_NAME_SET_P (thunk.alias))
215738fd1498Szrj         fprintf (f, " (asm: %s)",
215838fd1498Szrj 		 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (thunk.alias)));
215938fd1498Szrj       fprintf (f, "\n");
216038fd1498Szrj     }
216138fd1498Szrj 
216238fd1498Szrj   fprintf (f, "  Called by: ");
216338fd1498Szrj 
216438fd1498Szrj   profile_count sum = profile_count::zero ();
216538fd1498Szrj   for (edge = callers; edge; edge = edge->next_caller)
216638fd1498Szrj     {
216738fd1498Szrj       fprintf (f, "%s ", edge->caller->dump_name ());
216838fd1498Szrj       edge->dump_edge_flags (f);
216938fd1498Szrj       if (edge->count.initialized_p ())
217038fd1498Szrj 	sum += edge->count.ipa ();
217138fd1498Szrj     }
217238fd1498Szrj 
217338fd1498Szrj   fprintf (f, "\n  Calls: ");
217438fd1498Szrj   for (edge = callees; edge; edge = edge->next_callee)
217538fd1498Szrj     {
217638fd1498Szrj       fprintf (f, "%s ", edge->callee->dump_name ());
217738fd1498Szrj       edge->dump_edge_flags (f);
217838fd1498Szrj     }
217938fd1498Szrj   fprintf (f, "\n");
218038fd1498Szrj 
218138fd1498Szrj   if (count.ipa ().initialized_p ())
218238fd1498Szrj     {
218338fd1498Szrj       bool ok = true;
218438fd1498Szrj       bool min = false;
218538fd1498Szrj       ipa_ref *ref;
218638fd1498Szrj 
218738fd1498Szrj       FOR_EACH_ALIAS (this, ref)
218838fd1498Szrj 	if (dyn_cast <cgraph_node *> (ref->referring)->count.initialized_p ())
218938fd1498Szrj 	  sum += dyn_cast <cgraph_node *> (ref->referring)->count.ipa ();
219038fd1498Szrj 
219138fd1498Szrj       if (global.inlined_to
219238fd1498Szrj 	  || (symtab->state < EXPANSION
219338fd1498Szrj 	      && ultimate_alias_target () == this && only_called_directly_p ()))
219438fd1498Szrj 	ok = !count.ipa ().differs_from_p (sum);
219538fd1498Szrj       else if (count.ipa () > profile_count::from_gcov_type (100)
219638fd1498Szrj 	       && count.ipa () < sum.apply_scale (99, 100))
219738fd1498Szrj 	ok = false, min = true;
219838fd1498Szrj       if (!ok)
219938fd1498Szrj 	{
220038fd1498Szrj 	  fprintf (f, "   Invalid sum of caller counts ");
220138fd1498Szrj 	  sum.dump (f);
220238fd1498Szrj 	  if (min)
220338fd1498Szrj 	    fprintf (f, ", should be at most ");
220438fd1498Szrj 	  else
220538fd1498Szrj 	    fprintf (f, ", should be ");
220638fd1498Szrj 	  count.ipa ().dump (f);
220738fd1498Szrj 	  fprintf (f, "\n");
220838fd1498Szrj 	}
220938fd1498Szrj     }
221038fd1498Szrj 
221138fd1498Szrj   for (edge = indirect_calls; edge; edge = edge->next_callee)
221238fd1498Szrj     {
221338fd1498Szrj       if (edge->indirect_info->polymorphic)
221438fd1498Szrj 	{
221538fd1498Szrj           fprintf (f, "   Polymorphic indirect call of type ");
221638fd1498Szrj 	  print_generic_expr (f, edge->indirect_info->otr_type, TDF_SLIM);
221738fd1498Szrj 	  fprintf (f, " token:%i", (int) edge->indirect_info->otr_token);
221838fd1498Szrj 	}
221938fd1498Szrj       else
222038fd1498Szrj         fprintf (f, "   Indirect call");
222138fd1498Szrj       edge->dump_edge_flags (f);
222238fd1498Szrj       if (edge->indirect_info->param_index != -1)
222338fd1498Szrj 	{
222438fd1498Szrj 	  fprintf (f, " of param:%i", edge->indirect_info->param_index);
222538fd1498Szrj 	  if (edge->indirect_info->agg_contents)
222638fd1498Szrj 	   fprintf (f, " loaded from %s %s at offset %i",
222738fd1498Szrj 		    edge->indirect_info->member_ptr ? "member ptr" : "aggregate",
222838fd1498Szrj 		    edge->indirect_info->by_ref ? "passed by reference":"",
222938fd1498Szrj 		    (int)edge->indirect_info->offset);
223038fd1498Szrj 	  if (edge->indirect_info->vptr_changed)
223138fd1498Szrj 	    fprintf (f, " (vptr maybe changed)");
223238fd1498Szrj 	}
223338fd1498Szrj       fprintf (f, "\n");
223438fd1498Szrj       if (edge->indirect_info->polymorphic)
223538fd1498Szrj 	edge->indirect_info->context.dump (f);
223638fd1498Szrj     }
223738fd1498Szrj 
223838fd1498Szrj   if (instrumentation_clone)
223938fd1498Szrj     fprintf (f, "  Is instrumented version.\n");
224038fd1498Szrj   else if (instrumented_version)
224138fd1498Szrj     fprintf (f, "  Has instrumented version.\n");
224238fd1498Szrj }
224338fd1498Szrj 
224438fd1498Szrj /* Dump call graph node NODE to stderr.  */
224538fd1498Szrj 
224638fd1498Szrj DEBUG_FUNCTION void
debug(void)224738fd1498Szrj cgraph_node::debug (void)
224838fd1498Szrj {
224938fd1498Szrj   dump (stderr);
225038fd1498Szrj }
225138fd1498Szrj 
225238fd1498Szrj /* Dump the callgraph to file F.  */
225338fd1498Szrj 
225438fd1498Szrj void
dump_cgraph(FILE * f)225538fd1498Szrj cgraph_node::dump_cgraph (FILE *f)
225638fd1498Szrj {
225738fd1498Szrj   cgraph_node *node;
225838fd1498Szrj 
225938fd1498Szrj   fprintf (f, "callgraph:\n\n");
226038fd1498Szrj   FOR_EACH_FUNCTION (node)
226138fd1498Szrj     node->dump (f);
226238fd1498Szrj }
226338fd1498Szrj 
226438fd1498Szrj /* Return true when the DECL can possibly be inlined.  */
226538fd1498Szrj 
226638fd1498Szrj bool
cgraph_function_possibly_inlined_p(tree decl)226738fd1498Szrj cgraph_function_possibly_inlined_p (tree decl)
226838fd1498Szrj {
226938fd1498Szrj   if (!symtab->global_info_ready)
227038fd1498Szrj     return !DECL_UNINLINABLE (decl);
227138fd1498Szrj   return DECL_POSSIBLY_INLINED (decl);
227238fd1498Szrj }
227338fd1498Szrj 
227438fd1498Szrj /* cgraph_node is no longer nested function; update cgraph accordingly.  */
227538fd1498Szrj void
unnest(void)227638fd1498Szrj cgraph_node::unnest (void)
227738fd1498Szrj {
227838fd1498Szrj   cgraph_node **node2 = &origin->nested;
227938fd1498Szrj   gcc_assert (origin);
228038fd1498Szrj 
228138fd1498Szrj   while (*node2 != this)
228238fd1498Szrj     node2 = &(*node2)->next_nested;
228338fd1498Szrj   *node2 = next_nested;
228438fd1498Szrj   origin = NULL;
228538fd1498Szrj }
228638fd1498Szrj 
228738fd1498Szrj /* Return function availability.  See cgraph.h for description of individual
228838fd1498Szrj    return values.  */
228938fd1498Szrj enum availability
get_availability(symtab_node * ref)229038fd1498Szrj cgraph_node::get_availability (symtab_node *ref)
229138fd1498Szrj {
229238fd1498Szrj   if (ref)
229338fd1498Szrj     {
229438fd1498Szrj       cgraph_node *cref = dyn_cast <cgraph_node *> (ref);
229538fd1498Szrj       if (cref)
229638fd1498Szrj 	ref = cref->global.inlined_to;
229738fd1498Szrj     }
229838fd1498Szrj   enum availability avail;
229938fd1498Szrj   if (!analyzed)
230038fd1498Szrj     avail = AVAIL_NOT_AVAILABLE;
230138fd1498Szrj   else if (local.local)
230238fd1498Szrj     avail = AVAIL_LOCAL;
230338fd1498Szrj   else if (global.inlined_to)
230438fd1498Szrj     avail = AVAIL_AVAILABLE;
230538fd1498Szrj   else if (transparent_alias)
230638fd1498Szrj     ultimate_alias_target (&avail, ref);
230758e805e6Szrj   else if (ifunc_resolver
230838fd1498Szrj 	   || lookup_attribute ("noipa", DECL_ATTRIBUTES (decl)))
230938fd1498Szrj     avail = AVAIL_INTERPOSABLE;
231038fd1498Szrj   else if (!externally_visible)
231138fd1498Szrj     avail = AVAIL_AVAILABLE;
231238fd1498Szrj   /* If this is a reference from symbol itself and there are no aliases, we
231338fd1498Szrj      may be sure that the symbol was not interposed by something else because
231438fd1498Szrj      the symbol itself would be unreachable otherwise.
231538fd1498Szrj 
231638fd1498Szrj      Also comdat groups are always resolved in groups.  */
231738fd1498Szrj   else if ((this == ref && !has_aliases_p ())
231838fd1498Szrj            || (ref && get_comdat_group ()
231938fd1498Szrj                && get_comdat_group () == ref->get_comdat_group ()))
232038fd1498Szrj     avail = AVAIL_AVAILABLE;
232138fd1498Szrj   /* Inline functions are safe to be analyzed even if their symbol can
232238fd1498Szrj      be overwritten at runtime.  It is not meaningful to enforce any sane
232338fd1498Szrj      behavior on replacing inline function by different body.  */
232438fd1498Szrj   else if (DECL_DECLARED_INLINE_P (decl))
232538fd1498Szrj     avail = AVAIL_AVAILABLE;
232638fd1498Szrj 
232738fd1498Szrj   /* If the function can be overwritten, return OVERWRITABLE.  Take
232838fd1498Szrj      care at least of two notable extensions - the COMDAT functions
232938fd1498Szrj      used to share template instantiations in C++ (this is symmetric
233038fd1498Szrj      to code cp_cannot_inline_tree_fn and probably shall be shared and
233138fd1498Szrj      the inlinability hooks completely eliminated).  */
233238fd1498Szrj 
233338fd1498Szrj   else if (decl_replaceable_p (decl) && !DECL_EXTERNAL (decl))
233438fd1498Szrj     avail = AVAIL_INTERPOSABLE;
233538fd1498Szrj   else avail = AVAIL_AVAILABLE;
233638fd1498Szrj 
233738fd1498Szrj   return avail;
233838fd1498Szrj }
233938fd1498Szrj 
234038fd1498Szrj /* Worker for cgraph_node_can_be_local_p.  */
234138fd1498Szrj static bool
cgraph_node_cannot_be_local_p_1(cgraph_node * node,void *)234238fd1498Szrj cgraph_node_cannot_be_local_p_1 (cgraph_node *node, void *)
234338fd1498Szrj {
234438fd1498Szrj   return !(!node->force_output
234538fd1498Szrj 	   && ((DECL_COMDAT (node->decl)
234638fd1498Szrj 		&& !node->forced_by_abi
234738fd1498Szrj 		&& !node->used_from_object_file_p ()
234838fd1498Szrj 		&& !node->same_comdat_group)
234938fd1498Szrj 	       || !node->externally_visible));
235038fd1498Szrj }
235138fd1498Szrj 
235238fd1498Szrj /* Return true if cgraph_node can be made local for API change.
235338fd1498Szrj    Extern inline functions and C++ COMDAT functions can be made local
235438fd1498Szrj    at the expense of possible code size growth if function is used in multiple
235538fd1498Szrj    compilation units.  */
235638fd1498Szrj bool
can_be_local_p(void)235738fd1498Szrj cgraph_node::can_be_local_p (void)
235838fd1498Szrj {
235938fd1498Szrj   return (!address_taken
236038fd1498Szrj 	  && !call_for_symbol_thunks_and_aliases (cgraph_node_cannot_be_local_p_1,
236138fd1498Szrj 						NULL, true));
236238fd1498Szrj }
236338fd1498Szrj 
236438fd1498Szrj /* Call callback on cgraph_node, thunks and aliases associated to cgraph_node.
236538fd1498Szrj    When INCLUDE_OVERWRITABLE is false, overwritable symbols are
236638fd1498Szrj    skipped.  When EXCLUDE_VIRTUAL_THUNKS is true, virtual thunks are
236738fd1498Szrj    skipped.  */
236838fd1498Szrj bool
call_for_symbol_thunks_and_aliases(bool (* callback)(cgraph_node *,void *),void * data,bool include_overwritable,bool exclude_virtual_thunks)236938fd1498Szrj cgraph_node::call_for_symbol_thunks_and_aliases (bool (*callback)
237038fd1498Szrj 						   (cgraph_node *, void *),
237138fd1498Szrj 						 void *data,
237238fd1498Szrj 						 bool include_overwritable,
237338fd1498Szrj 						 bool exclude_virtual_thunks)
237438fd1498Szrj {
237538fd1498Szrj   cgraph_edge *e;
237638fd1498Szrj   ipa_ref *ref;
237738fd1498Szrj   enum availability avail = AVAIL_AVAILABLE;
237838fd1498Szrj 
237938fd1498Szrj   if (include_overwritable
238038fd1498Szrj       || (avail = get_availability ()) > AVAIL_INTERPOSABLE)
238138fd1498Szrj     {
238238fd1498Szrj       if (callback (this, data))
238338fd1498Szrj         return true;
238438fd1498Szrj     }
238538fd1498Szrj   FOR_EACH_ALIAS (this, ref)
238638fd1498Szrj     {
238738fd1498Szrj       cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring);
238838fd1498Szrj       if (include_overwritable
238938fd1498Szrj 	  || alias->get_availability () > AVAIL_INTERPOSABLE)
239038fd1498Szrj 	if (alias->call_for_symbol_thunks_and_aliases (callback, data,
239138fd1498Szrj 						     include_overwritable,
239238fd1498Szrj 						     exclude_virtual_thunks))
239338fd1498Szrj 	  return true;
239438fd1498Szrj     }
239538fd1498Szrj   if (avail <= AVAIL_INTERPOSABLE)
239638fd1498Szrj     return false;
239738fd1498Szrj   for (e = callers; e; e = e->next_caller)
239838fd1498Szrj     if (e->caller->thunk.thunk_p
239938fd1498Szrj 	&& (include_overwritable
240038fd1498Szrj 	    || e->caller->get_availability () > AVAIL_INTERPOSABLE)
240138fd1498Szrj 	&& !(exclude_virtual_thunks
240238fd1498Szrj 	     && e->caller->thunk.virtual_offset_p))
240338fd1498Szrj       if (e->caller->call_for_symbol_thunks_and_aliases (callback, data,
240438fd1498Szrj 						       include_overwritable,
240538fd1498Szrj 						       exclude_virtual_thunks))
240638fd1498Szrj 	return true;
240738fd1498Szrj 
240838fd1498Szrj   return false;
240938fd1498Szrj }
241038fd1498Szrj 
241138fd1498Szrj /* Worker to bring NODE local.  */
241238fd1498Szrj 
241338fd1498Szrj bool
make_local(cgraph_node * node,void *)241438fd1498Szrj cgraph_node::make_local (cgraph_node *node, void *)
241538fd1498Szrj {
241638fd1498Szrj   gcc_checking_assert (node->can_be_local_p ());
241738fd1498Szrj   if (DECL_COMDAT (node->decl) || DECL_EXTERNAL (node->decl))
241838fd1498Szrj     {
241938fd1498Szrj       node->make_decl_local ();
242038fd1498Szrj       node->set_section (NULL);
242138fd1498Szrj       node->set_comdat_group (NULL);
242238fd1498Szrj       node->externally_visible = false;
242338fd1498Szrj       node->forced_by_abi = false;
242438fd1498Szrj       node->local.local = true;
242538fd1498Szrj       node->set_section (NULL);
242638fd1498Szrj       node->unique_name = ((node->resolution == LDPR_PREVAILING_DEF_IRONLY
242738fd1498Szrj 			   || node->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP)
242838fd1498Szrj 			   && !flag_incremental_link);
242938fd1498Szrj       node->resolution = LDPR_PREVAILING_DEF_IRONLY;
243038fd1498Szrj       gcc_assert (node->get_availability () == AVAIL_LOCAL);
243138fd1498Szrj     }
243238fd1498Szrj   return false;
243338fd1498Szrj }
243438fd1498Szrj 
243538fd1498Szrj /* Bring cgraph node local.  */
243638fd1498Szrj 
243738fd1498Szrj void
make_local(void)243838fd1498Szrj cgraph_node::make_local (void)
243938fd1498Szrj {
244038fd1498Szrj   call_for_symbol_thunks_and_aliases (cgraph_node::make_local, NULL, true);
244138fd1498Szrj }
244238fd1498Szrj 
244338fd1498Szrj /* Worker to set nothrow flag.  */
244438fd1498Szrj 
244538fd1498Szrj static void
set_nothrow_flag_1(cgraph_node * node,bool nothrow,bool non_call,bool * changed)244638fd1498Szrj set_nothrow_flag_1 (cgraph_node *node, bool nothrow, bool non_call,
244738fd1498Szrj 		    bool *changed)
244838fd1498Szrj {
244938fd1498Szrj   cgraph_edge *e;
245038fd1498Szrj 
245138fd1498Szrj   if (nothrow && !TREE_NOTHROW (node->decl))
245238fd1498Szrj     {
245338fd1498Szrj       /* With non-call exceptions we can't say for sure if other function body
245438fd1498Szrj 	 was not possibly optimized to stil throw.  */
245538fd1498Szrj       if (!non_call || node->binds_to_current_def_p ())
245638fd1498Szrj 	{
245738fd1498Szrj 	  TREE_NOTHROW (node->decl) = true;
245838fd1498Szrj 	  *changed = true;
245938fd1498Szrj 	  for (e = node->callers; e; e = e->next_caller)
246038fd1498Szrj 	    e->can_throw_external = false;
246138fd1498Szrj 	}
246238fd1498Szrj     }
246338fd1498Szrj   else if (!nothrow && TREE_NOTHROW (node->decl))
246438fd1498Szrj     {
246538fd1498Szrj       TREE_NOTHROW (node->decl) = false;
246638fd1498Szrj       *changed = true;
246738fd1498Szrj     }
246838fd1498Szrj   ipa_ref *ref;
246938fd1498Szrj   FOR_EACH_ALIAS (node, ref)
247038fd1498Szrj     {
247138fd1498Szrj       cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring);
247238fd1498Szrj       if (!nothrow || alias->get_availability () > AVAIL_INTERPOSABLE)
247338fd1498Szrj 	set_nothrow_flag_1 (alias, nothrow, non_call, changed);
247438fd1498Szrj     }
247538fd1498Szrj   for (cgraph_edge *e = node->callers; e; e = e->next_caller)
247638fd1498Szrj     if (e->caller->thunk.thunk_p
247738fd1498Szrj 	&& (!nothrow || e->caller->get_availability () > AVAIL_INTERPOSABLE))
247838fd1498Szrj       set_nothrow_flag_1 (e->caller, nothrow, non_call, changed);
247938fd1498Szrj }
248038fd1498Szrj 
248138fd1498Szrj /* Set TREE_NOTHROW on NODE's decl and on aliases of NODE
248238fd1498Szrj    if any to NOTHROW.  */
248338fd1498Szrj 
248438fd1498Szrj bool
set_nothrow_flag(bool nothrow)248538fd1498Szrj cgraph_node::set_nothrow_flag (bool nothrow)
248638fd1498Szrj {
248738fd1498Szrj   bool changed = false;
248838fd1498Szrj   bool non_call = opt_for_fn (decl, flag_non_call_exceptions);
248938fd1498Szrj 
249038fd1498Szrj   if (!nothrow || get_availability () > AVAIL_INTERPOSABLE)
249138fd1498Szrj     set_nothrow_flag_1 (this, nothrow, non_call, &changed);
249238fd1498Szrj   else
249338fd1498Szrj     {
249438fd1498Szrj       ipa_ref *ref;
249538fd1498Szrj 
249638fd1498Szrj       FOR_EACH_ALIAS (this, ref)
249738fd1498Szrj 	{
249838fd1498Szrj 	  cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring);
249938fd1498Szrj 	  if (!nothrow || alias->get_availability () > AVAIL_INTERPOSABLE)
250038fd1498Szrj 	    set_nothrow_flag_1 (alias, nothrow, non_call, &changed);
250138fd1498Szrj 	}
250238fd1498Szrj     }
250338fd1498Szrj   return changed;
250438fd1498Szrj }
250538fd1498Szrj 
250638fd1498Szrj /* Worker to set malloc flag.  */
250738fd1498Szrj static void
set_malloc_flag_1(cgraph_node * node,bool malloc_p,bool * changed)250838fd1498Szrj set_malloc_flag_1 (cgraph_node *node, bool malloc_p, bool *changed)
250938fd1498Szrj {
251038fd1498Szrj   if (malloc_p && !DECL_IS_MALLOC (node->decl))
251138fd1498Szrj     {
251238fd1498Szrj       DECL_IS_MALLOC (node->decl) = true;
251338fd1498Szrj       *changed = true;
251438fd1498Szrj     }
251538fd1498Szrj 
251638fd1498Szrj   ipa_ref *ref;
251738fd1498Szrj   FOR_EACH_ALIAS (node, ref)
251838fd1498Szrj     {
251938fd1498Szrj       cgraph_node *alias = dyn_cast<cgraph_node *> (ref->referring);
252038fd1498Szrj       if (!malloc_p || alias->get_availability () > AVAIL_INTERPOSABLE)
252138fd1498Szrj 	set_malloc_flag_1 (alias, malloc_p, changed);
252238fd1498Szrj     }
252338fd1498Szrj 
252438fd1498Szrj   for (cgraph_edge *e = node->callers; e; e = e->next_caller)
252538fd1498Szrj     if (e->caller->thunk.thunk_p
252638fd1498Szrj 	&& (!malloc_p || e->caller->get_availability () > AVAIL_INTERPOSABLE))
252738fd1498Szrj       set_malloc_flag_1 (e->caller, malloc_p, changed);
252838fd1498Szrj }
252938fd1498Szrj 
253038fd1498Szrj /* Set DECL_IS_MALLOC on NODE's decl and on NODE's aliases if any.  */
253138fd1498Szrj 
253238fd1498Szrj bool
set_malloc_flag(bool malloc_p)253338fd1498Szrj cgraph_node::set_malloc_flag (bool malloc_p)
253438fd1498Szrj {
253538fd1498Szrj   bool changed = false;
253638fd1498Szrj 
253738fd1498Szrj   if (!malloc_p || get_availability () > AVAIL_INTERPOSABLE)
253838fd1498Szrj     set_malloc_flag_1 (this, malloc_p, &changed);
253938fd1498Szrj   else
254038fd1498Szrj     {
254138fd1498Szrj       ipa_ref *ref;
254238fd1498Szrj 
254338fd1498Szrj       FOR_EACH_ALIAS (this, ref)
254438fd1498Szrj 	{
254538fd1498Szrj 	  cgraph_node *alias = dyn_cast<cgraph_node *> (ref->referring);
254638fd1498Szrj 	  if (!malloc_p || alias->get_availability () > AVAIL_INTERPOSABLE)
254738fd1498Szrj 	    set_malloc_flag_1 (alias, malloc_p, &changed);
254838fd1498Szrj 	}
254938fd1498Szrj     }
255038fd1498Szrj   return changed;
255138fd1498Szrj }
255238fd1498Szrj 
255338fd1498Szrj /* Worker to set_const_flag.  */
255438fd1498Szrj 
255538fd1498Szrj static void
set_const_flag_1(cgraph_node * node,bool set_const,bool looping,bool * changed)255638fd1498Szrj set_const_flag_1 (cgraph_node *node, bool set_const, bool looping,
255738fd1498Szrj 		  bool *changed)
255838fd1498Szrj {
255938fd1498Szrj   /* Static constructors and destructors without a side effect can be
256038fd1498Szrj      optimized out.  */
256138fd1498Szrj   if (set_const && !looping)
256238fd1498Szrj     {
256338fd1498Szrj       if (DECL_STATIC_CONSTRUCTOR (node->decl))
256438fd1498Szrj 	{
256538fd1498Szrj 	  DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
256638fd1498Szrj 	  *changed = true;
256738fd1498Szrj 	}
256838fd1498Szrj       if (DECL_STATIC_DESTRUCTOR (node->decl))
256938fd1498Szrj 	{
257038fd1498Szrj 	  DECL_STATIC_DESTRUCTOR (node->decl) = 0;
257138fd1498Szrj 	  *changed = true;
257238fd1498Szrj 	}
257338fd1498Szrj     }
257438fd1498Szrj   if (!set_const)
257538fd1498Szrj     {
257638fd1498Szrj       if (TREE_READONLY (node->decl))
257738fd1498Szrj 	{
257838fd1498Szrj           TREE_READONLY (node->decl) = 0;
257938fd1498Szrj           DECL_LOOPING_CONST_OR_PURE_P (node->decl) = false;
258038fd1498Szrj 	  *changed = true;
258138fd1498Szrj 	}
258238fd1498Szrj     }
258338fd1498Szrj   else
258438fd1498Szrj     {
258538fd1498Szrj       /* Consider function:
258638fd1498Szrj 
258738fd1498Szrj 	 bool a(int *p)
258838fd1498Szrj 	 {
258938fd1498Szrj 	   return *p==*p;
259038fd1498Szrj 	 }
259138fd1498Szrj 
259238fd1498Szrj 	 During early optimization we will turn this into:
259338fd1498Szrj 
259438fd1498Szrj 	 bool a(int *p)
259538fd1498Szrj 	 {
259638fd1498Szrj 	   return true;
259738fd1498Szrj 	 }
259838fd1498Szrj 
259938fd1498Szrj 	 Now if this function will be detected as CONST however when interposed
260038fd1498Szrj 	 it may end up being just pure.  We always must assume the worst
260138fd1498Szrj 	 scenario here.  */
260238fd1498Szrj       if (TREE_READONLY (node->decl))
260338fd1498Szrj 	{
260438fd1498Szrj 	  if (!looping && DECL_LOOPING_CONST_OR_PURE_P (node->decl))
260538fd1498Szrj 	    {
260638fd1498Szrj               DECL_LOOPING_CONST_OR_PURE_P (node->decl) = false;
260738fd1498Szrj 	      *changed = true;
260838fd1498Szrj 	    }
260938fd1498Szrj 	}
261038fd1498Szrj       else if (node->binds_to_current_def_p ())
261138fd1498Szrj 	{
261238fd1498Szrj 	  TREE_READONLY (node->decl) = true;
261338fd1498Szrj           DECL_LOOPING_CONST_OR_PURE_P (node->decl) = looping;
261438fd1498Szrj 	  DECL_PURE_P (node->decl) = false;
261538fd1498Szrj 	  *changed = true;
261638fd1498Szrj 	}
261738fd1498Szrj       else
261838fd1498Szrj 	{
261938fd1498Szrj 	  if (dump_file && (dump_flags & TDF_DETAILS))
262038fd1498Szrj 	    fprintf (dump_file, "Dropping state to PURE because function does "
262138fd1498Szrj 		     "not bind to current def.\n");
262238fd1498Szrj 	  if (!DECL_PURE_P (node->decl))
262338fd1498Szrj 	    {
262438fd1498Szrj 	      DECL_PURE_P (node->decl) = true;
262538fd1498Szrj               DECL_LOOPING_CONST_OR_PURE_P (node->decl) = looping;
262638fd1498Szrj 	      *changed = true;
262738fd1498Szrj 	    }
262838fd1498Szrj 	  else if (!looping && DECL_LOOPING_CONST_OR_PURE_P (node->decl))
262938fd1498Szrj 	    {
263038fd1498Szrj               DECL_LOOPING_CONST_OR_PURE_P (node->decl) = false;
263138fd1498Szrj 	      *changed = true;
263238fd1498Szrj 	    }
263338fd1498Szrj 	}
263438fd1498Szrj     }
263538fd1498Szrj 
263638fd1498Szrj   ipa_ref *ref;
263738fd1498Szrj   FOR_EACH_ALIAS (node, ref)
263838fd1498Szrj     {
263938fd1498Szrj       cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring);
264038fd1498Szrj       if (!set_const || alias->get_availability () > AVAIL_INTERPOSABLE)
264138fd1498Szrj 	set_const_flag_1 (alias, set_const, looping, changed);
264238fd1498Szrj     }
264338fd1498Szrj   for (cgraph_edge *e = node->callers; e; e = e->next_caller)
264438fd1498Szrj     if (e->caller->thunk.thunk_p
264538fd1498Szrj 	&& (!set_const || e->caller->get_availability () > AVAIL_INTERPOSABLE))
264638fd1498Szrj       {
264738fd1498Szrj 	/* Virtual thunks access virtual offset in the vtable, so they can
264838fd1498Szrj 	   only be pure, never const.  */
264938fd1498Szrj         if (set_const
265038fd1498Szrj 	    && (e->caller->thunk.virtual_offset_p
265138fd1498Szrj 	        || !node->binds_to_current_def_p (e->caller)))
265238fd1498Szrj 	  *changed |= e->caller->set_pure_flag (true, looping);
265338fd1498Szrj 	else
265438fd1498Szrj 	  set_const_flag_1 (e->caller, set_const, looping, changed);
265538fd1498Szrj       }
265638fd1498Szrj }
265738fd1498Szrj 
265838fd1498Szrj /* If SET_CONST is true, mark function, aliases and thunks to be ECF_CONST.
265938fd1498Szrj    If SET_CONST if false, clear the flag.
266038fd1498Szrj 
266138fd1498Szrj    When setting the flag be careful about possible interposition and
266238fd1498Szrj    do not set the flag for functions that can be interposet and set pure
266338fd1498Szrj    flag for functions that can bind to other definition.
266438fd1498Szrj 
266538fd1498Szrj    Return true if any change was done. */
266638fd1498Szrj 
266738fd1498Szrj bool
set_const_flag(bool set_const,bool looping)266838fd1498Szrj cgraph_node::set_const_flag (bool set_const, bool looping)
266938fd1498Szrj {
267038fd1498Szrj   bool changed = false;
267138fd1498Szrj   if (!set_const || get_availability () > AVAIL_INTERPOSABLE)
267238fd1498Szrj     set_const_flag_1 (this, set_const, looping, &changed);
267338fd1498Szrj   else
267438fd1498Szrj     {
267538fd1498Szrj       ipa_ref *ref;
267638fd1498Szrj 
267738fd1498Szrj       FOR_EACH_ALIAS (this, ref)
267838fd1498Szrj 	{
267938fd1498Szrj 	  cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring);
268038fd1498Szrj 	  if (!set_const || alias->get_availability () > AVAIL_INTERPOSABLE)
268138fd1498Szrj 	    set_const_flag_1 (alias, set_const, looping, &changed);
268238fd1498Szrj 	}
268338fd1498Szrj     }
268438fd1498Szrj   return changed;
268538fd1498Szrj }
268638fd1498Szrj 
268738fd1498Szrj /* Info used by set_pure_flag_1.  */
268838fd1498Szrj 
268938fd1498Szrj struct set_pure_flag_info
269038fd1498Szrj {
269138fd1498Szrj   bool pure;
269238fd1498Szrj   bool looping;
269338fd1498Szrj   bool changed;
269438fd1498Szrj };
269538fd1498Szrj 
269638fd1498Szrj /* Worker to set_pure_flag.  */
269738fd1498Szrj 
269838fd1498Szrj static bool
set_pure_flag_1(cgraph_node * node,void * data)269938fd1498Szrj set_pure_flag_1 (cgraph_node *node, void *data)
270038fd1498Szrj {
270138fd1498Szrj   struct set_pure_flag_info *info = (struct set_pure_flag_info *)data;
270238fd1498Szrj   /* Static constructors and destructors without a side effect can be
270338fd1498Szrj      optimized out.  */
270438fd1498Szrj   if (info->pure && !info->looping)
270538fd1498Szrj     {
270638fd1498Szrj       if (DECL_STATIC_CONSTRUCTOR (node->decl))
270738fd1498Szrj 	{
270838fd1498Szrj 	  DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
270938fd1498Szrj 	  info->changed = true;
271038fd1498Szrj 	}
271138fd1498Szrj       if (DECL_STATIC_DESTRUCTOR (node->decl))
271238fd1498Szrj 	{
271338fd1498Szrj 	  DECL_STATIC_DESTRUCTOR (node->decl) = 0;
271438fd1498Szrj 	  info->changed = true;
271538fd1498Szrj 	}
271638fd1498Szrj     }
271738fd1498Szrj   if (info->pure)
271838fd1498Szrj     {
271938fd1498Szrj       if (!DECL_PURE_P (node->decl) && !TREE_READONLY (node->decl))
272038fd1498Szrj 	{
272138fd1498Szrj           DECL_PURE_P (node->decl) = true;
272238fd1498Szrj           DECL_LOOPING_CONST_OR_PURE_P (node->decl) = info->looping;
272338fd1498Szrj 	  info->changed = true;
272438fd1498Szrj 	}
272538fd1498Szrj       else if (DECL_LOOPING_CONST_OR_PURE_P (node->decl)
272638fd1498Szrj 	       && !info->looping)
272738fd1498Szrj 	{
272838fd1498Szrj           DECL_LOOPING_CONST_OR_PURE_P (node->decl) = false;
272938fd1498Szrj 	  info->changed = true;
273038fd1498Szrj 	}
273138fd1498Szrj     }
273238fd1498Szrj   else
273338fd1498Szrj     {
273438fd1498Szrj       if (DECL_PURE_P (node->decl))
273538fd1498Szrj 	{
273638fd1498Szrj           DECL_PURE_P (node->decl) = false;
273738fd1498Szrj           DECL_LOOPING_CONST_OR_PURE_P (node->decl) = false;
273838fd1498Szrj 	  info->changed = true;
273938fd1498Szrj 	}
274038fd1498Szrj     }
274138fd1498Szrj   return false;
274238fd1498Szrj }
274338fd1498Szrj 
274438fd1498Szrj /* Set DECL_PURE_P on cgraph_node's decl and on aliases of the node
274538fd1498Szrj    if any to PURE.
274638fd1498Szrj 
274738fd1498Szrj    When setting the flag, be careful about possible interposition.
274838fd1498Szrj    Return true if any change was done. */
274938fd1498Szrj 
275038fd1498Szrj bool
set_pure_flag(bool pure,bool looping)275138fd1498Szrj cgraph_node::set_pure_flag (bool pure, bool looping)
275238fd1498Szrj {
275338fd1498Szrj   struct set_pure_flag_info info = {pure, looping, false};
275438fd1498Szrj   if (!pure)
275538fd1498Szrj     looping = false;
275638fd1498Szrj   call_for_symbol_thunks_and_aliases (set_pure_flag_1, &info, !pure, true);
275738fd1498Szrj   return info.changed;
275838fd1498Szrj }
275938fd1498Szrj 
276038fd1498Szrj /* Return true when cgraph_node can not return or throw and thus
276138fd1498Szrj    it is safe to ignore its side effects for IPA analysis.  */
276238fd1498Szrj 
276338fd1498Szrj bool
cannot_return_p(void)276438fd1498Szrj cgraph_node::cannot_return_p (void)
276538fd1498Szrj {
276638fd1498Szrj   int flags = flags_from_decl_or_type (decl);
276738fd1498Szrj   if (!opt_for_fn (decl, flag_exceptions))
276838fd1498Szrj     return (flags & ECF_NORETURN) != 0;
276938fd1498Szrj   else
277038fd1498Szrj     return ((flags & (ECF_NORETURN | ECF_NOTHROW))
277138fd1498Szrj 	     == (ECF_NORETURN | ECF_NOTHROW));
277238fd1498Szrj }
277338fd1498Szrj 
277438fd1498Szrj /* Return true when call of edge can not lead to return from caller
277538fd1498Szrj    and thus it is safe to ignore its side effects for IPA analysis
277638fd1498Szrj    when computing side effects of the caller.
277738fd1498Szrj    FIXME: We could actually mark all edges that have no reaching
277838fd1498Szrj    patch to the exit block or throw to get better results.  */
277938fd1498Szrj bool
cannot_lead_to_return_p(void)278038fd1498Szrj cgraph_edge::cannot_lead_to_return_p (void)
278138fd1498Szrj {
278238fd1498Szrj   if (caller->cannot_return_p ())
278338fd1498Szrj     return true;
278438fd1498Szrj   if (indirect_unknown_callee)
278538fd1498Szrj     {
278638fd1498Szrj       int flags = indirect_info->ecf_flags;
278738fd1498Szrj       if (!opt_for_fn (caller->decl, flag_exceptions))
278838fd1498Szrj 	return (flags & ECF_NORETURN) != 0;
278938fd1498Szrj       else
279038fd1498Szrj 	return ((flags & (ECF_NORETURN | ECF_NOTHROW))
279138fd1498Szrj 		 == (ECF_NORETURN | ECF_NOTHROW));
279238fd1498Szrj     }
279338fd1498Szrj   else
279438fd1498Szrj     return callee->cannot_return_p ();
279538fd1498Szrj }
279638fd1498Szrj 
279738fd1498Szrj /* Return true if the call can be hot.  */
279838fd1498Szrj 
279938fd1498Szrj bool
maybe_hot_p(void)280038fd1498Szrj cgraph_edge::maybe_hot_p (void)
280138fd1498Szrj {
280238fd1498Szrj   if (!maybe_hot_count_p (NULL, count.ipa ()))
280338fd1498Szrj     return false;
280438fd1498Szrj   if (caller->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED
280538fd1498Szrj       || (callee
280638fd1498Szrj 	  && callee->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED))
280738fd1498Szrj     return false;
280838fd1498Szrj   if (caller->frequency > NODE_FREQUENCY_UNLIKELY_EXECUTED
280938fd1498Szrj       && (callee
281038fd1498Szrj 	  && callee->frequency <= NODE_FREQUENCY_EXECUTED_ONCE))
281138fd1498Szrj     return false;
281238fd1498Szrj   if (opt_for_fn (caller->decl, optimize_size))
281338fd1498Szrj     return false;
281438fd1498Szrj   if (caller->frequency == NODE_FREQUENCY_HOT)
281538fd1498Szrj     return true;
281638fd1498Szrj   /* If profile is now known yet, be conservative.
281738fd1498Szrj      FIXME: this predicate is used by early inliner and can do better there.  */
281838fd1498Szrj   if (symtab->state < IPA_SSA)
281938fd1498Szrj     return true;
282038fd1498Szrj   if (caller->frequency == NODE_FREQUENCY_EXECUTED_ONCE
282138fd1498Szrj       && sreal_frequency () * 2 < 3)
282238fd1498Szrj     return false;
282338fd1498Szrj   if (PARAM_VALUE (HOT_BB_FREQUENCY_FRACTION) == 0
282438fd1498Szrj       || sreal_frequency () * PARAM_VALUE (HOT_BB_FREQUENCY_FRACTION) <= 1)
282538fd1498Szrj     return false;
282638fd1498Szrj   return true;
282738fd1498Szrj }
282838fd1498Szrj 
282938fd1498Szrj /* Worker for cgraph_can_remove_if_no_direct_calls_p.  */
283038fd1498Szrj 
283138fd1498Szrj static bool
nonremovable_p(cgraph_node * node,void *)283238fd1498Szrj nonremovable_p (cgraph_node *node, void *)
283338fd1498Szrj {
283438fd1498Szrj   return !node->can_remove_if_no_direct_calls_and_refs_p ();
283538fd1498Szrj }
283638fd1498Szrj 
283738fd1498Szrj /* Return true if whole comdat group can be removed if there are no direct
283838fd1498Szrj    calls to THIS.  */
283938fd1498Szrj 
284038fd1498Szrj bool
can_remove_if_no_direct_calls_p(bool will_inline)284138fd1498Szrj cgraph_node::can_remove_if_no_direct_calls_p (bool will_inline)
284238fd1498Szrj {
284338fd1498Szrj   struct ipa_ref *ref;
284438fd1498Szrj 
284538fd1498Szrj   /* For local symbols or non-comdat group it is the same as
284638fd1498Szrj      can_remove_if_no_direct_calls_p.  */
284738fd1498Szrj   if (!externally_visible || !same_comdat_group)
284838fd1498Szrj     {
284938fd1498Szrj       if (DECL_EXTERNAL (decl))
285038fd1498Szrj 	return true;
285138fd1498Szrj       if (address_taken)
285238fd1498Szrj 	return false;
285338fd1498Szrj       return !call_for_symbol_and_aliases (nonremovable_p, NULL, true);
285438fd1498Szrj     }
285538fd1498Szrj 
285638fd1498Szrj   if (will_inline && address_taken)
285738fd1498Szrj     return false;
285838fd1498Szrj 
285938fd1498Szrj   /* Otheriwse check if we can remove the symbol itself and then verify
286038fd1498Szrj      that only uses of the comdat groups are direct call to THIS
286138fd1498Szrj      or its aliases.   */
286238fd1498Szrj   if (!can_remove_if_no_direct_calls_and_refs_p ())
286338fd1498Szrj     return false;
286438fd1498Szrj 
286538fd1498Szrj   /* Check that all refs come from within the comdat group.  */
286638fd1498Szrj   for (int i = 0; iterate_referring (i, ref); i++)
286738fd1498Szrj     if (ref->referring->get_comdat_group () != get_comdat_group ())
286838fd1498Szrj       return false;
286938fd1498Szrj 
287038fd1498Szrj   struct cgraph_node *target = ultimate_alias_target ();
287138fd1498Szrj   for (cgraph_node *next = dyn_cast<cgraph_node *> (same_comdat_group);
287238fd1498Szrj        next != this; next = dyn_cast<cgraph_node *> (next->same_comdat_group))
287338fd1498Szrj     {
287438fd1498Szrj       if (!externally_visible)
287538fd1498Szrj 	continue;
287638fd1498Szrj       if (!next->alias
287738fd1498Szrj 	  && !next->can_remove_if_no_direct_calls_and_refs_p ())
287838fd1498Szrj 	return false;
287938fd1498Szrj 
288038fd1498Szrj       /* If we see different symbol than THIS, be sure to check calls.  */
288138fd1498Szrj       if (next->ultimate_alias_target () != target)
288238fd1498Szrj 	for (cgraph_edge *e = next->callers; e; e = e->next_caller)
288338fd1498Szrj 	  if (e->caller->get_comdat_group () != get_comdat_group ()
288438fd1498Szrj 	      || will_inline)
288538fd1498Szrj 	    return false;
288638fd1498Szrj 
288738fd1498Szrj       /* If function is not being inlined, we care only about
288838fd1498Szrj 	 references outside of the comdat group.  */
288938fd1498Szrj       if (!will_inline)
289038fd1498Szrj         for (int i = 0; next->iterate_referring (i, ref); i++)
289138fd1498Szrj 	  if (ref->referring->get_comdat_group () != get_comdat_group ())
289238fd1498Szrj 	    return false;
289338fd1498Szrj     }
289438fd1498Szrj   return true;
289538fd1498Szrj }
289638fd1498Szrj 
289738fd1498Szrj /* Return true when function cgraph_node can be expected to be removed
289838fd1498Szrj    from program when direct calls in this compilation unit are removed.
289938fd1498Szrj 
290038fd1498Szrj    As a special case COMDAT functions are
290138fd1498Szrj    cgraph_can_remove_if_no_direct_calls_p while the are not
290238fd1498Szrj    cgraph_only_called_directly_p (it is possible they are called from other
290338fd1498Szrj    unit)
290438fd1498Szrj 
290538fd1498Szrj    This function behaves as cgraph_only_called_directly_p because eliminating
290638fd1498Szrj    all uses of COMDAT function does not make it necessarily disappear from
290738fd1498Szrj    the program unless we are compiling whole program or we do LTO.  In this
290838fd1498Szrj    case we know we win since dynamic linking will not really discard the
290938fd1498Szrj    linkonce section.  */
291038fd1498Szrj 
291138fd1498Szrj bool
will_be_removed_from_program_if_no_direct_calls_p(bool will_inline)291238fd1498Szrj cgraph_node::will_be_removed_from_program_if_no_direct_calls_p
291338fd1498Szrj 	 (bool will_inline)
291438fd1498Szrj {
291538fd1498Szrj   gcc_assert (!global.inlined_to);
291638fd1498Szrj   if (DECL_EXTERNAL (decl))
291738fd1498Szrj     return true;
291838fd1498Szrj 
291938fd1498Szrj   if (!in_lto_p && !flag_whole_program)
292038fd1498Szrj     {
292138fd1498Szrj       /* If the symbol is in comdat group, we need to verify that whole comdat
292238fd1498Szrj 	 group becomes unreachable.  Technically we could skip references from
292338fd1498Szrj 	 within the group, too.  */
292438fd1498Szrj       if (!only_called_directly_p ())
292538fd1498Szrj 	return false;
292638fd1498Szrj       if (same_comdat_group && externally_visible)
292738fd1498Szrj 	{
292838fd1498Szrj 	  struct cgraph_node *target = ultimate_alias_target ();
292938fd1498Szrj 
293038fd1498Szrj 	  if (will_inline && address_taken)
293138fd1498Szrj 	    return true;
293238fd1498Szrj 	  for (cgraph_node *next = dyn_cast<cgraph_node *> (same_comdat_group);
293338fd1498Szrj 	       next != this;
293438fd1498Szrj 	       next = dyn_cast<cgraph_node *> (next->same_comdat_group))
293538fd1498Szrj 	    {
293638fd1498Szrj 	      if (!externally_visible)
293738fd1498Szrj 		continue;
293838fd1498Szrj 	      if (!next->alias
293938fd1498Szrj 		  && !next->only_called_directly_p ())
294038fd1498Szrj 		return false;
294138fd1498Szrj 
294238fd1498Szrj 	      /* If we see different symbol than THIS,
294338fd1498Szrj 		 be sure to check calls.  */
294438fd1498Szrj 	      if (next->ultimate_alias_target () != target)
294538fd1498Szrj 		for (cgraph_edge *e = next->callers; e; e = e->next_caller)
294638fd1498Szrj 		  if (e->caller->get_comdat_group () != get_comdat_group ()
294738fd1498Szrj 		      || will_inline)
294838fd1498Szrj 		    return false;
294938fd1498Szrj 	    }
295038fd1498Szrj 	}
295138fd1498Szrj       return true;
295238fd1498Szrj     }
295338fd1498Szrj   else
295438fd1498Szrj     return can_remove_if_no_direct_calls_p (will_inline);
295538fd1498Szrj }
295638fd1498Szrj 
295738fd1498Szrj 
295838fd1498Szrj /* Worker for cgraph_only_called_directly_p.  */
295938fd1498Szrj 
296038fd1498Szrj static bool
cgraph_not_only_called_directly_p_1(cgraph_node * node,void *)296138fd1498Szrj cgraph_not_only_called_directly_p_1 (cgraph_node *node, void *)
296238fd1498Szrj {
296338fd1498Szrj   return !node->only_called_directly_or_aliased_p ();
296438fd1498Szrj }
296538fd1498Szrj 
296638fd1498Szrj /* Return true when function cgraph_node and all its aliases are only called
296738fd1498Szrj    directly.
296838fd1498Szrj    i.e. it is not externally visible, address was not taken and
296938fd1498Szrj    it is not used in any other non-standard way.  */
297038fd1498Szrj 
297138fd1498Szrj bool
only_called_directly_p(void)297238fd1498Szrj cgraph_node::only_called_directly_p (void)
297338fd1498Szrj {
297438fd1498Szrj   gcc_assert (ultimate_alias_target () == this);
297538fd1498Szrj   return !call_for_symbol_and_aliases (cgraph_not_only_called_directly_p_1,
297638fd1498Szrj 				       NULL, true);
297738fd1498Szrj }
297838fd1498Szrj 
297938fd1498Szrj 
298038fd1498Szrj /* Collect all callers of NODE.  Worker for collect_callers_of_node.  */
298138fd1498Szrj 
298238fd1498Szrj static bool
collect_callers_of_node_1(cgraph_node * node,void * data)298338fd1498Szrj collect_callers_of_node_1 (cgraph_node *node, void *data)
298438fd1498Szrj {
298538fd1498Szrj   vec<cgraph_edge *> *redirect_callers = (vec<cgraph_edge *> *)data;
298638fd1498Szrj   cgraph_edge *cs;
298738fd1498Szrj   enum availability avail;
298838fd1498Szrj   node->ultimate_alias_target (&avail);
298938fd1498Szrj 
299038fd1498Szrj   if (avail > AVAIL_INTERPOSABLE)
299138fd1498Szrj     for (cs = node->callers; cs != NULL; cs = cs->next_caller)
299238fd1498Szrj       if (!cs->indirect_inlining_edge
299338fd1498Szrj 	  && !cs->caller->thunk.thunk_p)
299438fd1498Szrj         redirect_callers->safe_push (cs);
299538fd1498Szrj   return false;
299638fd1498Szrj }
299738fd1498Szrj 
299838fd1498Szrj /* Collect all callers of cgraph_node and its aliases that are known to lead to
299938fd1498Szrj    cgraph_node (i.e. are not overwritable).  */
300038fd1498Szrj 
300138fd1498Szrj vec<cgraph_edge *>
collect_callers(void)300238fd1498Szrj cgraph_node::collect_callers (void)
300338fd1498Szrj {
300438fd1498Szrj   vec<cgraph_edge *> redirect_callers = vNULL;
300538fd1498Szrj   call_for_symbol_thunks_and_aliases (collect_callers_of_node_1,
300638fd1498Szrj 				    &redirect_callers, false);
300738fd1498Szrj   return redirect_callers;
300838fd1498Szrj }
300938fd1498Szrj 
3010*e215fc28Szrj 
3011*e215fc28Szrj /* Return TRUE if NODE2 a clone of NODE or is equivalent to it.  Return
3012*e215fc28Szrj    optimistically true if this cannot be determined.  */
301338fd1498Szrj 
301438fd1498Szrj static bool
clone_of_p(cgraph_node * node,cgraph_node * node2)301538fd1498Szrj clone_of_p (cgraph_node *node, cgraph_node *node2)
301638fd1498Szrj {
301738fd1498Szrj   node = node->ultimate_alias_target ();
301838fd1498Szrj   node2 = node2->ultimate_alias_target ();
301938fd1498Szrj 
3020*e215fc28Szrj   if (node2->clone_of == node
3021*e215fc28Szrj       || node2->former_clone_of == node->decl)
3022*e215fc28Szrj     return true;
3023*e215fc28Szrj 
3024*e215fc28Szrj   if (!node->thunk.thunk_p && !node->former_thunk_p ())
3025*e215fc28Szrj     {
3026*e215fc28Szrj       while (node2 && node->decl != node2->decl)
3027*e215fc28Szrj 	node2 = node2->clone_of;
3028*e215fc28Szrj       return node2 != NULL;
3029*e215fc28Szrj     }
3030*e215fc28Szrj 
303138fd1498Szrj   /* There are no virtual clones of thunks so check former_clone_of or if we
303238fd1498Szrj      might have skipped thunks because this adjustments are no longer
303338fd1498Szrj      necessary.  */
3034*e215fc28Szrj   while (node->thunk.thunk_p || node->former_thunk_p ())
303538fd1498Szrj     {
303638fd1498Szrj       if (!node->thunk.this_adjusting)
303738fd1498Szrj 	return false;
3038*e215fc28Szrj       /* In case of instrumented expanded thunks, which can have multiple calls
3039*e215fc28Szrj 	 in them, we do not know how to continue and just have to be
3040*e215fc28Szrj 	 optimistic.  */
3041*e215fc28Szrj       if (node->callees->next_callee)
3042*e215fc28Szrj 	return true;
304338fd1498Szrj       node = node->callees->callee->ultimate_alias_target ();
304438fd1498Szrj 
304538fd1498Szrj       if (!node2->clone.args_to_skip
304638fd1498Szrj 	  || !bitmap_bit_p (node2->clone.args_to_skip, 0))
304738fd1498Szrj 	return false;
304838fd1498Szrj       if (node2->former_clone_of == node->decl)
304938fd1498Szrj 	return true;
3050*e215fc28Szrj 
3051*e215fc28Szrj       cgraph_node *n2 = node2;
3052*e215fc28Szrj       while (n2 && node->decl != n2->decl)
3053*e215fc28Szrj 	n2 = n2->clone_of;
3054*e215fc28Szrj       if (n2)
3055*e215fc28Szrj 	return true;
305638fd1498Szrj     }
305738fd1498Szrj 
3058*e215fc28Szrj   return false;
305938fd1498Szrj }
306038fd1498Szrj 
306138fd1498Szrj /* Verify edge count and frequency.  */
306238fd1498Szrj 
306338fd1498Szrj bool
verify_count()306438fd1498Szrj cgraph_edge::verify_count ()
306538fd1498Szrj {
306638fd1498Szrj   bool error_found = false;
306738fd1498Szrj   if (!count.verify ())
306838fd1498Szrj     {
306938fd1498Szrj       error ("caller edge count invalid");
307038fd1498Szrj       error_found = true;
307138fd1498Szrj     }
307238fd1498Szrj   return error_found;
307338fd1498Szrj }
307438fd1498Szrj 
307538fd1498Szrj /* Switch to THIS_CFUN if needed and print STMT to stderr.  */
307638fd1498Szrj static void
cgraph_debug_gimple_stmt(function * this_cfun,gimple * stmt)307738fd1498Szrj cgraph_debug_gimple_stmt (function *this_cfun, gimple *stmt)
307838fd1498Szrj {
307938fd1498Szrj   bool fndecl_was_null = false;
308038fd1498Szrj   /* debug_gimple_stmt needs correct cfun */
308138fd1498Szrj   if (cfun != this_cfun)
308238fd1498Szrj     set_cfun (this_cfun);
308338fd1498Szrj   /* ...and an actual current_function_decl */
308438fd1498Szrj   if (!current_function_decl)
308538fd1498Szrj     {
308638fd1498Szrj       current_function_decl = this_cfun->decl;
308738fd1498Szrj       fndecl_was_null = true;
308838fd1498Szrj     }
308938fd1498Szrj   debug_gimple_stmt (stmt);
309038fd1498Szrj   if (fndecl_was_null)
309138fd1498Szrj     current_function_decl = NULL;
309238fd1498Szrj }
309338fd1498Szrj 
309438fd1498Szrj /* Verify that call graph edge corresponds to DECL from the associated
309538fd1498Szrj    statement.  Return true if the verification should fail.  */
309638fd1498Szrj 
309738fd1498Szrj bool
verify_corresponds_to_fndecl(tree decl)309838fd1498Szrj cgraph_edge::verify_corresponds_to_fndecl (tree decl)
309938fd1498Szrj {
310038fd1498Szrj   cgraph_node *node;
310138fd1498Szrj 
310238fd1498Szrj   if (!decl || callee->global.inlined_to)
310338fd1498Szrj     return false;
310438fd1498Szrj   if (symtab->state == LTO_STREAMING)
310538fd1498Szrj     return false;
310638fd1498Szrj   node = cgraph_node::get (decl);
310738fd1498Szrj 
310838fd1498Szrj   /* We do not know if a node from a different partition is an alias or what it
310938fd1498Szrj      aliases and therefore cannot do the former_clone_of check reliably.  When
311038fd1498Szrj      body_removed is set, we have lost all information about what was alias or
311138fd1498Szrj      thunk of and also cannot proceed.  */
311238fd1498Szrj   if (!node
311338fd1498Szrj       || node->body_removed
311438fd1498Szrj       || node->in_other_partition
311538fd1498Szrj       || callee->icf_merged
311638fd1498Szrj       || callee->in_other_partition)
311738fd1498Szrj     return false;
311838fd1498Szrj 
311938fd1498Szrj   node = node->ultimate_alias_target ();
312038fd1498Szrj 
312138fd1498Szrj   /* Optimizers can redirect unreachable calls or calls triggering undefined
312238fd1498Szrj      behavior to builtin_unreachable.  */
312338fd1498Szrj   if (DECL_BUILT_IN_CLASS (callee->decl) == BUILT_IN_NORMAL
312438fd1498Szrj       && DECL_FUNCTION_CODE (callee->decl) == BUILT_IN_UNREACHABLE)
312538fd1498Szrj     return false;
312638fd1498Szrj 
312738fd1498Szrj   if (callee->former_clone_of != node->decl
312838fd1498Szrj       && (node != callee->ultimate_alias_target ())
312938fd1498Szrj       && !clone_of_p (node, callee))
313038fd1498Szrj     return true;
313138fd1498Szrj   else
313238fd1498Szrj     return false;
313338fd1498Szrj }
313438fd1498Szrj 
313538fd1498Szrj /* Verify cgraph nodes of given cgraph node.  */
313638fd1498Szrj DEBUG_FUNCTION void
verify_node(void)313738fd1498Szrj cgraph_node::verify_node (void)
313838fd1498Szrj {
313938fd1498Szrj   cgraph_edge *e;
314038fd1498Szrj   function *this_cfun = DECL_STRUCT_FUNCTION (decl);
314138fd1498Szrj   basic_block this_block;
314238fd1498Szrj   gimple_stmt_iterator gsi;
314338fd1498Szrj   bool error_found = false;
314438fd1498Szrj 
314538fd1498Szrj   if (seen_error ())
314638fd1498Szrj     return;
314738fd1498Szrj 
314838fd1498Szrj   timevar_push (TV_CGRAPH_VERIFY);
314938fd1498Szrj   error_found |= verify_base ();
315038fd1498Szrj   for (e = callees; e; e = e->next_callee)
315138fd1498Szrj     if (e->aux)
315238fd1498Szrj       {
315338fd1498Szrj 	error ("aux field set for edge %s->%s",
315438fd1498Szrj 	       identifier_to_locale (e->caller->name ()),
315538fd1498Szrj 	       identifier_to_locale (e->callee->name ()));
315638fd1498Szrj 	error_found = true;
315738fd1498Szrj       }
315838fd1498Szrj   if (!count.verify ())
315938fd1498Szrj     {
316038fd1498Szrj       error ("cgraph count invalid");
316138fd1498Szrj       error_found = true;
316238fd1498Szrj     }
316338fd1498Szrj   if (global.inlined_to && same_comdat_group)
316438fd1498Szrj     {
316538fd1498Szrj       error ("inline clone in same comdat group list");
316638fd1498Szrj       error_found = true;
316738fd1498Szrj     }
316838fd1498Szrj   if (!definition && !in_other_partition && local.local)
316938fd1498Szrj     {
317038fd1498Szrj       error ("local symbols must be defined");
317138fd1498Szrj       error_found = true;
317238fd1498Szrj     }
317338fd1498Szrj   if (global.inlined_to && externally_visible)
317438fd1498Szrj     {
317538fd1498Szrj       error ("externally visible inline clone");
317638fd1498Szrj       error_found = true;
317738fd1498Szrj     }
317838fd1498Szrj   if (global.inlined_to && address_taken)
317938fd1498Szrj     {
318038fd1498Szrj       error ("inline clone with address taken");
318138fd1498Szrj       error_found = true;
318238fd1498Szrj     }
318338fd1498Szrj   if (global.inlined_to && force_output)
318438fd1498Szrj     {
318538fd1498Szrj       error ("inline clone is forced to output");
318638fd1498Szrj       error_found = true;
318738fd1498Szrj     }
318838fd1498Szrj   for (e = indirect_calls; e; e = e->next_callee)
318938fd1498Szrj     {
319038fd1498Szrj       if (e->aux)
319138fd1498Szrj 	{
319238fd1498Szrj 	  error ("aux field set for indirect edge from %s",
319338fd1498Szrj 		 identifier_to_locale (e->caller->name ()));
319438fd1498Szrj 	  error_found = true;
319538fd1498Szrj 	}
319638fd1498Szrj       if (!e->indirect_unknown_callee
319738fd1498Szrj 	  || !e->indirect_info)
319838fd1498Szrj 	{
319938fd1498Szrj 	  error ("An indirect edge from %s is not marked as indirect or has "
320038fd1498Szrj 		 "associated indirect_info, the corresponding statement is: ",
320138fd1498Szrj 		 identifier_to_locale (e->caller->name ()));
320238fd1498Szrj 	  cgraph_debug_gimple_stmt (this_cfun, e->call_stmt);
320338fd1498Szrj 	  error_found = true;
320438fd1498Szrj 	}
320538fd1498Szrj     }
320638fd1498Szrj   bool check_comdat = comdat_local_p ();
320738fd1498Szrj   for (e = callers; e; e = e->next_caller)
320838fd1498Szrj     {
320938fd1498Szrj       if (e->verify_count ())
321038fd1498Szrj 	error_found = true;
321138fd1498Szrj       if (check_comdat
321238fd1498Szrj 	  && !in_same_comdat_group_p (e->caller))
321338fd1498Szrj 	{
321438fd1498Szrj 	  error ("comdat-local function called by %s outside its comdat",
321538fd1498Szrj 		 identifier_to_locale (e->caller->name ()));
321638fd1498Szrj 	  error_found = true;
321738fd1498Szrj 	}
321838fd1498Szrj       if (!e->inline_failed)
321938fd1498Szrj 	{
322038fd1498Szrj 	  if (global.inlined_to
322138fd1498Szrj 	      != (e->caller->global.inlined_to
322238fd1498Szrj 		  ? e->caller->global.inlined_to : e->caller))
322338fd1498Szrj 	    {
322438fd1498Szrj 	      error ("inlined_to pointer is wrong");
322538fd1498Szrj 	      error_found = true;
322638fd1498Szrj 	    }
322738fd1498Szrj 	  if (callers->next_caller)
322838fd1498Szrj 	    {
322938fd1498Szrj 	      error ("multiple inline callers");
323038fd1498Szrj 	      error_found = true;
323138fd1498Szrj 	    }
323238fd1498Szrj 	}
323338fd1498Szrj       else
323438fd1498Szrj 	if (global.inlined_to)
323538fd1498Szrj 	  {
323638fd1498Szrj 	    error ("inlined_to pointer set for noninline callers");
323738fd1498Szrj 	    error_found = true;
323838fd1498Szrj 	  }
323938fd1498Szrj     }
324038fd1498Szrj   for (e = callees; e; e = e->next_callee)
324138fd1498Szrj     {
324238fd1498Szrj       if (e->verify_count ())
324338fd1498Szrj 	error_found = true;
324438fd1498Szrj       if (gimple_has_body_p (e->caller->decl)
324538fd1498Szrj 	  && !e->caller->global.inlined_to
324638fd1498Szrj 	  && !e->speculative
324738fd1498Szrj 	  /* Optimized out calls are redirected to __builtin_unreachable.  */
324838fd1498Szrj 	  && (e->count.nonzero_p ()
324938fd1498Szrj 	      || ! e->callee->decl
325038fd1498Szrj 	      || DECL_BUILT_IN_CLASS (e->callee->decl) != BUILT_IN_NORMAL
325138fd1498Szrj 	      || DECL_FUNCTION_CODE (e->callee->decl) != BUILT_IN_UNREACHABLE)
325238fd1498Szrj 	  && count
325338fd1498Szrj 	      == ENTRY_BLOCK_PTR_FOR_FN (DECL_STRUCT_FUNCTION (decl))->count
325438fd1498Szrj 	  && (!e->count.ipa_p ()
325538fd1498Szrj 	      && e->count.differs_from_p (gimple_bb (e->call_stmt)->count)))
325638fd1498Szrj 	{
325738fd1498Szrj 	  error ("caller edge count does not match BB count");
325838fd1498Szrj 	  fprintf (stderr, "edge count: ");
325938fd1498Szrj 	  e->count.dump (stderr);
326038fd1498Szrj 	  fprintf (stderr, "\n bb count: ");
326138fd1498Szrj 	  gimple_bb (e->call_stmt)->count.dump (stderr);
326238fd1498Szrj 	  fprintf (stderr, "\n");
326338fd1498Szrj 	  error_found = true;
326438fd1498Szrj 	}
326538fd1498Szrj     }
326638fd1498Szrj   for (e = indirect_calls; e; e = e->next_callee)
326738fd1498Szrj     {
326838fd1498Szrj       if (e->verify_count ())
326938fd1498Szrj 	error_found = true;
327038fd1498Szrj       if (gimple_has_body_p (e->caller->decl)
327138fd1498Szrj 	  && !e->caller->global.inlined_to
327238fd1498Szrj 	  && !e->speculative
327338fd1498Szrj 	  && e->count.ipa_p ()
327438fd1498Szrj 	  && count
327538fd1498Szrj 	      == ENTRY_BLOCK_PTR_FOR_FN (DECL_STRUCT_FUNCTION (decl))->count
327638fd1498Szrj 	  && (!e->count.ipa_p ()
327738fd1498Szrj 	      && e->count.differs_from_p (gimple_bb (e->call_stmt)->count)))
327838fd1498Szrj 	{
327938fd1498Szrj 	  error ("indirect call count does not match BB count");
328038fd1498Szrj 	  fprintf (stderr, "edge count: ");
328138fd1498Szrj 	  e->count.dump (stderr);
328238fd1498Szrj 	  fprintf (stderr, "\n bb count: ");
328338fd1498Szrj 	  gimple_bb (e->call_stmt)->count.dump (stderr);
328438fd1498Szrj 	  fprintf (stderr, "\n");
328538fd1498Szrj 	  error_found = true;
328638fd1498Szrj 	}
328738fd1498Szrj     }
328838fd1498Szrj   if (!callers && global.inlined_to)
328938fd1498Szrj     {
329038fd1498Szrj       error ("inlined_to pointer is set but no predecessors found");
329138fd1498Szrj       error_found = true;
329238fd1498Szrj     }
329338fd1498Szrj   if (global.inlined_to == this)
329438fd1498Szrj     {
329538fd1498Szrj       error ("inlined_to pointer refers to itself");
329638fd1498Szrj       error_found = true;
329738fd1498Szrj     }
329838fd1498Szrj 
329938fd1498Szrj   if (clone_of)
330038fd1498Szrj     {
330138fd1498Szrj       cgraph_node *n;
330238fd1498Szrj       for (n = clone_of->clones; n; n = n->next_sibling_clone)
330338fd1498Szrj 	if (n == this)
330438fd1498Szrj 	  break;
330538fd1498Szrj       if (!n)
330638fd1498Szrj 	{
330738fd1498Szrj 	  error ("cgraph_node has wrong clone_of");
330838fd1498Szrj 	  error_found = true;
330938fd1498Szrj 	}
331038fd1498Szrj     }
331138fd1498Szrj   if (clones)
331238fd1498Szrj     {
331338fd1498Szrj       cgraph_node *n;
331438fd1498Szrj       for (n = clones; n; n = n->next_sibling_clone)
331538fd1498Szrj 	if (n->clone_of != this)
331638fd1498Szrj 	  break;
331738fd1498Szrj       if (n)
331838fd1498Szrj 	{
331938fd1498Szrj 	  error ("cgraph_node has wrong clone list");
332038fd1498Szrj 	  error_found = true;
332138fd1498Szrj 	}
332238fd1498Szrj     }
332338fd1498Szrj   if ((prev_sibling_clone || next_sibling_clone) && !clone_of)
332438fd1498Szrj     {
332538fd1498Szrj        error ("cgraph_node is in clone list but it is not clone");
332638fd1498Szrj        error_found = true;
332738fd1498Szrj     }
332838fd1498Szrj   if (!prev_sibling_clone && clone_of && clone_of->clones != this)
332938fd1498Szrj     {
333038fd1498Szrj       error ("cgraph_node has wrong prev_clone pointer");
333138fd1498Szrj       error_found = true;
333238fd1498Szrj     }
333338fd1498Szrj   if (prev_sibling_clone && prev_sibling_clone->next_sibling_clone != this)
333438fd1498Szrj     {
333538fd1498Szrj       error ("double linked list of clones corrupted");
333638fd1498Szrj       error_found = true;
333738fd1498Szrj     }
333838fd1498Szrj 
333938fd1498Szrj   if (analyzed && alias)
334038fd1498Szrj     {
334138fd1498Szrj       bool ref_found = false;
334238fd1498Szrj       int i;
334338fd1498Szrj       ipa_ref *ref = NULL;
334438fd1498Szrj 
334538fd1498Szrj       if (callees)
334638fd1498Szrj 	{
334738fd1498Szrj 	  error ("Alias has call edges");
334838fd1498Szrj           error_found = true;
334938fd1498Szrj 	}
335038fd1498Szrj       for (i = 0; iterate_reference (i, ref); i++)
335138fd1498Szrj 	if (ref->use == IPA_REF_CHKP)
335238fd1498Szrj 	  ;
335338fd1498Szrj 	else if (ref->use != IPA_REF_ALIAS)
335438fd1498Szrj 	  {
335538fd1498Szrj 	    error ("Alias has non-alias reference");
335638fd1498Szrj 	    error_found = true;
335738fd1498Szrj 	  }
335838fd1498Szrj 	else if (ref_found)
335938fd1498Szrj 	  {
336038fd1498Szrj 	    error ("Alias has more than one alias reference");
336138fd1498Szrj 	    error_found = true;
336238fd1498Szrj 	  }
336338fd1498Szrj 	else
336438fd1498Szrj 	  ref_found = true;
336538fd1498Szrj       if (!ref_found)
336638fd1498Szrj 	{
336738fd1498Szrj 	  error ("Analyzed alias has no reference");
336838fd1498Szrj 	  error_found = true;
336938fd1498Szrj 	}
337038fd1498Szrj     }
337138fd1498Szrj 
337238fd1498Szrj   /* Check instrumented version reference.  */
337338fd1498Szrj   if (instrumented_version
337438fd1498Szrj       && instrumented_version->instrumented_version != this)
337538fd1498Szrj     {
337638fd1498Szrj       error ("Instrumentation clone does not reference original node");
337738fd1498Szrj       error_found = true;
337838fd1498Szrj     }
337938fd1498Szrj 
338038fd1498Szrj   /* Cannot have orig_decl for not instrumented nodes.  */
338138fd1498Szrj   if (!instrumentation_clone && orig_decl)
338238fd1498Szrj     {
338338fd1498Szrj       error ("Not instrumented node has non-NULL original declaration");
338438fd1498Szrj       error_found = true;
338538fd1498Szrj     }
338638fd1498Szrj 
338738fd1498Szrj   /* If original not instrumented node still exists then we may check
338838fd1498Szrj      original declaration is set properly.  */
338938fd1498Szrj   if (instrumented_version
339038fd1498Szrj       && orig_decl
339138fd1498Szrj       && orig_decl != instrumented_version->decl)
339238fd1498Szrj     {
339338fd1498Szrj       error ("Instrumented node has wrong original declaration");
339438fd1498Szrj       error_found = true;
339538fd1498Szrj     }
339638fd1498Szrj 
339738fd1498Szrj   /* Check all nodes have chkp reference to their instrumented versions.  */
339838fd1498Szrj   if (analyzed
339938fd1498Szrj       && instrumented_version
340038fd1498Szrj       && !instrumentation_clone)
340138fd1498Szrj     {
340238fd1498Szrj       bool ref_found = false;
340338fd1498Szrj       int i;
340438fd1498Szrj       struct ipa_ref *ref;
340538fd1498Szrj 
340638fd1498Szrj       for (i = 0; iterate_reference (i, ref); i++)
340738fd1498Szrj 	if (ref->use == IPA_REF_CHKP)
340838fd1498Szrj 	  {
340938fd1498Szrj 	    if (ref_found)
341038fd1498Szrj 	      {
341138fd1498Szrj 		error ("Node has more than one chkp reference");
341238fd1498Szrj 		error_found = true;
341338fd1498Szrj 	      }
341438fd1498Szrj 	    if (ref->referred != instrumented_version)
341538fd1498Szrj 	      {
341638fd1498Szrj 		error ("Wrong node is referenced with chkp reference");
341738fd1498Szrj 		error_found = true;
341838fd1498Szrj 	      }
341938fd1498Szrj 	    ref_found = true;
342038fd1498Szrj 	  }
342138fd1498Szrj 
342238fd1498Szrj       if (!ref_found)
342338fd1498Szrj 	{
342438fd1498Szrj 	  error ("Analyzed node has no reference to instrumented version");
342538fd1498Szrj 	  error_found = true;
342638fd1498Szrj 	}
342738fd1498Szrj     }
342838fd1498Szrj 
342938fd1498Szrj   if (instrumentation_clone
343038fd1498Szrj       && DECL_BUILT_IN_CLASS (decl) == NOT_BUILT_IN)
343138fd1498Szrj     {
343238fd1498Szrj       tree name = DECL_ASSEMBLER_NAME (decl);
343338fd1498Szrj       tree orig_name = DECL_ASSEMBLER_NAME (orig_decl);
343438fd1498Szrj 
343538fd1498Szrj       if (!IDENTIFIER_TRANSPARENT_ALIAS (name)
343638fd1498Szrj 	  || TREE_CHAIN (name) != orig_name)
343738fd1498Szrj 	{
343838fd1498Szrj 	  error ("Alias chain for instrumented node is broken");
343938fd1498Szrj 	  error_found = true;
344038fd1498Szrj 	}
344138fd1498Szrj     }
344238fd1498Szrj 
344338fd1498Szrj   if (analyzed && thunk.thunk_p)
344438fd1498Szrj     {
344538fd1498Szrj       if (!callees)
344638fd1498Szrj 	{
344738fd1498Szrj 	  error ("No edge out of thunk node");
344838fd1498Szrj           error_found = true;
344938fd1498Szrj 	}
345038fd1498Szrj       else if (callees->next_callee)
345138fd1498Szrj 	{
345238fd1498Szrj 	  error ("More than one edge out of thunk node");
345338fd1498Szrj           error_found = true;
345438fd1498Szrj 	}
345538fd1498Szrj       if (gimple_has_body_p (decl) && !global.inlined_to)
345638fd1498Szrj         {
345738fd1498Szrj 	  error ("Thunk is not supposed to have body");
345838fd1498Szrj           error_found = true;
345938fd1498Szrj         }
346038fd1498Szrj       if (thunk.add_pointer_bounds_args
346138fd1498Szrj 	  && !instrumented_version->semantically_equivalent_p (callees->callee))
346238fd1498Szrj 	{
346338fd1498Szrj 	  error ("Instrumentation thunk has wrong edge callee");
346438fd1498Szrj           error_found = true;
346538fd1498Szrj 	}
346638fd1498Szrj     }
346738fd1498Szrj   else if (analyzed && gimple_has_body_p (decl)
346838fd1498Szrj 	   && !TREE_ASM_WRITTEN (decl)
346938fd1498Szrj 	   && (!DECL_EXTERNAL (decl) || global.inlined_to)
347038fd1498Szrj 	   && !flag_wpa)
347138fd1498Szrj     {
347238fd1498Szrj       if (this_cfun->cfg)
347338fd1498Szrj 	{
347438fd1498Szrj 	  hash_set<gimple *> stmts;
347538fd1498Szrj 	  int i;
347638fd1498Szrj 	  ipa_ref *ref = NULL;
347738fd1498Szrj 
347838fd1498Szrj 	  /* Reach the trees by walking over the CFG, and note the
347938fd1498Szrj 	     enclosing basic-blocks in the call edges.  */
348038fd1498Szrj 	  FOR_EACH_BB_FN (this_block, this_cfun)
348138fd1498Szrj 	    {
348238fd1498Szrj 	      for (gsi = gsi_start_phis (this_block);
348338fd1498Szrj 		   !gsi_end_p (gsi); gsi_next (&gsi))
348438fd1498Szrj 		stmts.add (gsi_stmt (gsi));
348538fd1498Szrj 	      for (gsi = gsi_start_bb (this_block);
348638fd1498Szrj 		   !gsi_end_p (gsi);
348738fd1498Szrj 		   gsi_next (&gsi))
348838fd1498Szrj 		{
348938fd1498Szrj 		  gimple *stmt = gsi_stmt (gsi);
349038fd1498Szrj 		  stmts.add (stmt);
349138fd1498Szrj 		  if (is_gimple_call (stmt))
349238fd1498Szrj 		    {
349338fd1498Szrj 		      cgraph_edge *e = get_edge (stmt);
349438fd1498Szrj 		      tree decl = gimple_call_fndecl (stmt);
349538fd1498Szrj 		      if (e)
349638fd1498Szrj 			{
349738fd1498Szrj 			  if (e->aux)
349838fd1498Szrj 			    {
349938fd1498Szrj 			      error ("shared call_stmt:");
350038fd1498Szrj 			      cgraph_debug_gimple_stmt (this_cfun, stmt);
350138fd1498Szrj 			      error_found = true;
350238fd1498Szrj 			    }
350338fd1498Szrj 			  if (!e->indirect_unknown_callee)
350438fd1498Szrj 			    {
350538fd1498Szrj 			      if (e->verify_corresponds_to_fndecl (decl))
350638fd1498Szrj 				{
350738fd1498Szrj 				  error ("edge points to wrong declaration:");
350838fd1498Szrj 				  debug_tree (e->callee->decl);
350938fd1498Szrj 				  fprintf (stderr," Instead of:");
351038fd1498Szrj 				  debug_tree (decl);
351138fd1498Szrj 				  error_found = true;
351238fd1498Szrj 				}
351338fd1498Szrj 			    }
351438fd1498Szrj 			  else if (decl)
351538fd1498Szrj 			    {
351638fd1498Szrj 			      error ("an indirect edge with unknown callee "
351738fd1498Szrj 				     "corresponding to a call_stmt with "
351838fd1498Szrj 				     "a known declaration:");
351938fd1498Szrj 			      error_found = true;
352038fd1498Szrj 			      cgraph_debug_gimple_stmt (this_cfun, e->call_stmt);
352138fd1498Szrj 			    }
352238fd1498Szrj 			  e->aux = (void *)1;
352338fd1498Szrj 			}
352438fd1498Szrj 		      else if (decl)
352538fd1498Szrj 			{
352638fd1498Szrj 			  error ("missing callgraph edge for call stmt:");
352738fd1498Szrj 			  cgraph_debug_gimple_stmt (this_cfun, stmt);
352838fd1498Szrj 			  error_found = true;
352938fd1498Szrj 			}
353038fd1498Szrj 		    }
353138fd1498Szrj 		}
353238fd1498Szrj 	      }
353338fd1498Szrj 	    for (i = 0; iterate_reference (i, ref); i++)
353438fd1498Szrj 	      if (ref->stmt && !stmts.contains (ref->stmt))
353538fd1498Szrj 		{
353638fd1498Szrj 		  error ("reference to dead statement");
353738fd1498Szrj 		  cgraph_debug_gimple_stmt (this_cfun, ref->stmt);
353838fd1498Szrj 		  error_found = true;
353938fd1498Szrj 		}
354038fd1498Szrj 	}
354138fd1498Szrj       else
354238fd1498Szrj 	/* No CFG available?!  */
354338fd1498Szrj 	gcc_unreachable ();
354438fd1498Szrj 
354538fd1498Szrj       for (e = callees; e; e = e->next_callee)
354638fd1498Szrj 	{
354738fd1498Szrj 	  if (!e->aux)
354838fd1498Szrj 	    {
354938fd1498Szrj 	      error ("edge %s->%s has no corresponding call_stmt",
355038fd1498Szrj 		     identifier_to_locale (e->caller->name ()),
355138fd1498Szrj 		     identifier_to_locale (e->callee->name ()));
355238fd1498Szrj 	      cgraph_debug_gimple_stmt (this_cfun, e->call_stmt);
355338fd1498Szrj 	      error_found = true;
355438fd1498Szrj 	    }
355538fd1498Szrj 	  e->aux = 0;
355638fd1498Szrj 	}
355738fd1498Szrj       for (e = indirect_calls; e; e = e->next_callee)
355838fd1498Szrj 	{
355938fd1498Szrj 	  if (!e->aux && !e->speculative)
356038fd1498Szrj 	    {
356138fd1498Szrj 	      error ("an indirect edge from %s has no corresponding call_stmt",
356238fd1498Szrj 		     identifier_to_locale (e->caller->name ()));
356338fd1498Szrj 	      cgraph_debug_gimple_stmt (this_cfun, e->call_stmt);
356438fd1498Szrj 	      error_found = true;
356538fd1498Szrj 	    }
356638fd1498Szrj 	  e->aux = 0;
356738fd1498Szrj 	}
356838fd1498Szrj     }
356938fd1498Szrj   if (error_found)
357038fd1498Szrj     {
357138fd1498Szrj       dump (stderr);
357238fd1498Szrj       internal_error ("verify_cgraph_node failed");
357338fd1498Szrj     }
357438fd1498Szrj   timevar_pop (TV_CGRAPH_VERIFY);
357538fd1498Szrj }
357638fd1498Szrj 
357738fd1498Szrj /* Verify whole cgraph structure.  */
357838fd1498Szrj DEBUG_FUNCTION void
verify_cgraph_nodes(void)357938fd1498Szrj cgraph_node::verify_cgraph_nodes (void)
358038fd1498Szrj {
358138fd1498Szrj   cgraph_node *node;
358238fd1498Szrj 
358338fd1498Szrj   if (seen_error ())
358438fd1498Szrj     return;
358538fd1498Szrj 
358638fd1498Szrj   FOR_EACH_FUNCTION (node)
358738fd1498Szrj     node->verify ();
358838fd1498Szrj }
358938fd1498Szrj 
359038fd1498Szrj /* Walk the alias chain to return the function cgraph_node is alias of.
359138fd1498Szrj    Walk through thunks, too.
359238fd1498Szrj    When AVAILABILITY is non-NULL, get minimal availability in the chain.
359338fd1498Szrj    When REF is non-NULL, assume that reference happens in symbol REF
359438fd1498Szrj    when determining the availability.  */
359538fd1498Szrj 
359638fd1498Szrj cgraph_node *
function_symbol(enum availability * availability,struct symtab_node * ref)359738fd1498Szrj cgraph_node::function_symbol (enum availability *availability,
359838fd1498Szrj 			      struct symtab_node *ref)
359938fd1498Szrj {
360038fd1498Szrj   cgraph_node *node = ultimate_alias_target (availability, ref);
360138fd1498Szrj 
360238fd1498Szrj   while (node->thunk.thunk_p)
360338fd1498Szrj     {
360438fd1498Szrj       ref = node;
360538fd1498Szrj       node = node->callees->callee;
360638fd1498Szrj       if (availability)
360738fd1498Szrj 	{
360838fd1498Szrj 	  enum availability a;
360938fd1498Szrj 	  a = node->get_availability (ref);
361038fd1498Szrj 	  if (a < *availability)
361138fd1498Szrj 	    *availability = a;
361238fd1498Szrj 	}
361338fd1498Szrj       node = node->ultimate_alias_target (availability, ref);
361438fd1498Szrj     }
361538fd1498Szrj   return node;
361638fd1498Szrj }
361738fd1498Szrj 
361838fd1498Szrj /* Walk the alias chain to return the function cgraph_node is alias of.
361938fd1498Szrj    Walk through non virtual thunks, too.  Thus we return either a function
362038fd1498Szrj    or a virtual thunk node.
362138fd1498Szrj    When AVAILABILITY is non-NULL, get minimal availability in the chain.
362238fd1498Szrj    When REF is non-NULL, assume that reference happens in symbol REF
362338fd1498Szrj    when determining the availability.  */
362438fd1498Szrj 
362538fd1498Szrj cgraph_node *
function_or_virtual_thunk_symbol(enum availability * availability,struct symtab_node * ref)362638fd1498Szrj cgraph_node::function_or_virtual_thunk_symbol
362738fd1498Szrj 				(enum availability *availability,
362838fd1498Szrj 				 struct symtab_node *ref)
362938fd1498Szrj {
363038fd1498Szrj   cgraph_node *node = ultimate_alias_target (availability, ref);
363138fd1498Szrj 
363238fd1498Szrj   while (node->thunk.thunk_p && !node->thunk.virtual_offset_p)
363338fd1498Szrj     {
363438fd1498Szrj       ref = node;
363538fd1498Szrj       node = node->callees->callee;
363638fd1498Szrj       if (availability)
363738fd1498Szrj 	{
363838fd1498Szrj 	  enum availability a;
363938fd1498Szrj 	  a = node->get_availability (ref);
364038fd1498Szrj 	  if (a < *availability)
364138fd1498Szrj 	    *availability = a;
364238fd1498Szrj 	}
364338fd1498Szrj       node = node->ultimate_alias_target (availability, ref);
364438fd1498Szrj     }
364538fd1498Szrj   return node;
364638fd1498Szrj }
364738fd1498Szrj 
364838fd1498Szrj /* When doing LTO, read cgraph_node's body from disk if it is not already
364938fd1498Szrj    present.  */
365038fd1498Szrj 
365138fd1498Szrj bool
get_untransformed_body(void)365238fd1498Szrj cgraph_node::get_untransformed_body (void)
365338fd1498Szrj {
365438fd1498Szrj   lto_file_decl_data *file_data;
365538fd1498Szrj   const char *data, *name;
365638fd1498Szrj   size_t len;
365738fd1498Szrj   tree decl = this->decl;
365838fd1498Szrj 
365938fd1498Szrj   /* Check if body is already there.  Either we have gimple body or
366038fd1498Szrj      the function is thunk and in that case we set DECL_ARGUMENTS.  */
366138fd1498Szrj   if (DECL_ARGUMENTS (decl) || gimple_has_body_p (decl))
366238fd1498Szrj     return false;
366338fd1498Szrj 
366438fd1498Szrj   gcc_assert (in_lto_p && !DECL_RESULT (decl));
366538fd1498Szrj 
366638fd1498Szrj   timevar_push (TV_IPA_LTO_GIMPLE_IN);
366738fd1498Szrj 
366838fd1498Szrj   file_data = lto_file_data;
366938fd1498Szrj   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
367038fd1498Szrj 
367138fd1498Szrj   /* We may have renamed the declaration, e.g., a static function.  */
367238fd1498Szrj   name = lto_get_decl_name_mapping (file_data, name);
367338fd1498Szrj   struct lto_in_decl_state *decl_state
367438fd1498Szrj 	 = lto_get_function_in_decl_state (file_data, decl);
367538fd1498Szrj 
367638fd1498Szrj   data = lto_get_section_data (file_data, LTO_section_function_body,
367738fd1498Szrj 			       name, &len, decl_state->compressed);
367838fd1498Szrj   if (!data)
367938fd1498Szrj     fatal_error (input_location, "%s: section %s is missing",
368038fd1498Szrj 		 file_data->file_name,
368138fd1498Szrj 		 name);
368238fd1498Szrj 
368338fd1498Szrj   gcc_assert (DECL_STRUCT_FUNCTION (decl) == NULL);
368438fd1498Szrj 
368538fd1498Szrj   lto_input_function_body (file_data, this, data);
368638fd1498Szrj   lto_stats.num_function_bodies++;
368738fd1498Szrj   lto_free_section_data (file_data, LTO_section_function_body, name,
368838fd1498Szrj 			 data, len, decl_state->compressed);
368938fd1498Szrj   lto_free_function_in_decl_state_for_node (this);
369038fd1498Szrj   /* Keep lto file data so ipa-inline-analysis knows about cross module
369138fd1498Szrj      inlining.  */
369238fd1498Szrj 
369338fd1498Szrj   timevar_pop (TV_IPA_LTO_GIMPLE_IN);
369438fd1498Szrj 
369538fd1498Szrj   return true;
369638fd1498Szrj }
369738fd1498Szrj 
369838fd1498Szrj /* Prepare function body.  When doing LTO, read cgraph_node's body from disk
369938fd1498Szrj    if it is not already present.  When some IPA transformations are scheduled,
370038fd1498Szrj    apply them.  */
370138fd1498Szrj 
370238fd1498Szrj bool
get_body(void)370338fd1498Szrj cgraph_node::get_body (void)
370438fd1498Szrj {
370538fd1498Szrj   bool updated;
370638fd1498Szrj 
370738fd1498Szrj   updated = get_untransformed_body ();
370838fd1498Szrj 
370938fd1498Szrj   /* Getting transformed body makes no sense for inline clones;
371038fd1498Szrj      we should never use this on real clones because they are materialized
371138fd1498Szrj      early.
371238fd1498Szrj      TODO: Materializing clones here will likely lead to smaller LTRANS
371338fd1498Szrj      footprint. */
371438fd1498Szrj   gcc_assert (!global.inlined_to && !clone_of);
371538fd1498Szrj   if (ipa_transforms_to_apply.exists ())
371638fd1498Szrj     {
371738fd1498Szrj       opt_pass *saved_current_pass = current_pass;
371838fd1498Szrj       FILE *saved_dump_file = dump_file;
371938fd1498Szrj       const char *saved_dump_file_name = dump_file_name;
372038fd1498Szrj       dump_flags_t saved_dump_flags = dump_flags;
372138fd1498Szrj       dump_file_name = NULL;
372238fd1498Szrj       dump_file = NULL;
372338fd1498Szrj 
372438fd1498Szrj       push_cfun (DECL_STRUCT_FUNCTION (decl));
372538fd1498Szrj       execute_all_ipa_transforms ();
372638fd1498Szrj       cgraph_edge::rebuild_edges ();
372738fd1498Szrj       free_dominance_info (CDI_DOMINATORS);
372838fd1498Szrj       free_dominance_info (CDI_POST_DOMINATORS);
372938fd1498Szrj       pop_cfun ();
373038fd1498Szrj       updated = true;
373138fd1498Szrj 
373238fd1498Szrj       current_pass = saved_current_pass;
373338fd1498Szrj       dump_file = saved_dump_file;
373438fd1498Szrj       dump_file_name = saved_dump_file_name;
373538fd1498Szrj       dump_flags = saved_dump_flags;
373638fd1498Szrj     }
373738fd1498Szrj   return updated;
373838fd1498Szrj }
373938fd1498Szrj 
374038fd1498Szrj /* Return the DECL_STRUCT_FUNCTION of the function.  */
374138fd1498Szrj 
374238fd1498Szrj struct function *
get_fun(void)374338fd1498Szrj cgraph_node::get_fun (void)
374438fd1498Szrj {
374538fd1498Szrj   cgraph_node *node = this;
374638fd1498Szrj   struct function *fun = DECL_STRUCT_FUNCTION (node->decl);
374738fd1498Szrj 
374838fd1498Szrj   while (!fun && node->clone_of)
374938fd1498Szrj     {
375038fd1498Szrj       node = node->clone_of;
375138fd1498Szrj       fun = DECL_STRUCT_FUNCTION (node->decl);
375238fd1498Szrj     }
375338fd1498Szrj 
375438fd1498Szrj   return fun;
375538fd1498Szrj }
375638fd1498Szrj 
375738fd1498Szrj /* Verify if the type of the argument matches that of the function
375838fd1498Szrj    declaration.  If we cannot verify this or there is a mismatch,
375938fd1498Szrj    return false.  */
376038fd1498Szrj 
376138fd1498Szrj static bool
gimple_check_call_args(gimple * stmt,tree fndecl,bool args_count_match)376238fd1498Szrj gimple_check_call_args (gimple *stmt, tree fndecl, bool args_count_match)
376338fd1498Szrj {
376438fd1498Szrj   tree parms, p;
376538fd1498Szrj   unsigned int i, nargs;
376638fd1498Szrj 
376738fd1498Szrj   /* Calls to internal functions always match their signature.  */
376838fd1498Szrj   if (gimple_call_internal_p (stmt))
376938fd1498Szrj     return true;
377038fd1498Szrj 
377138fd1498Szrj   nargs = gimple_call_num_args (stmt);
377238fd1498Szrj 
377338fd1498Szrj   /* Get argument types for verification.  */
377438fd1498Szrj   if (fndecl)
377538fd1498Szrj     parms = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
377638fd1498Szrj   else
377738fd1498Szrj     parms = TYPE_ARG_TYPES (gimple_call_fntype (stmt));
377838fd1498Szrj 
377938fd1498Szrj   /* Verify if the type of the argument matches that of the function
378038fd1498Szrj      declaration.  If we cannot verify this or there is a mismatch,
378138fd1498Szrj      return false.  */
378238fd1498Szrj   if (fndecl && DECL_ARGUMENTS (fndecl))
378338fd1498Szrj     {
378438fd1498Szrj       for (i = 0, p = DECL_ARGUMENTS (fndecl);
378538fd1498Szrj 	   i < nargs;
378638fd1498Szrj 	   i++, p = DECL_CHAIN (p))
378738fd1498Szrj 	{
378838fd1498Szrj 	  tree arg;
378938fd1498Szrj 	  /* We cannot distinguish a varargs function from the case
379038fd1498Szrj 	     of excess parameters, still deferring the inlining decision
379138fd1498Szrj 	     to the callee is possible.  */
379238fd1498Szrj 	  if (!p)
379338fd1498Szrj 	    break;
379438fd1498Szrj 	  arg = gimple_call_arg (stmt, i);
379538fd1498Szrj 	  if (p == error_mark_node
379638fd1498Szrj 	      || DECL_ARG_TYPE (p) == error_mark_node
379738fd1498Szrj 	      || arg == error_mark_node
379838fd1498Szrj 	      || (!types_compatible_p (DECL_ARG_TYPE (p), TREE_TYPE (arg))
379938fd1498Szrj 		  && !fold_convertible_p (DECL_ARG_TYPE (p), arg)))
380038fd1498Szrj             return false;
380138fd1498Szrj 	}
380238fd1498Szrj       if (args_count_match && p)
380338fd1498Szrj 	return false;
380438fd1498Szrj     }
380538fd1498Szrj   else if (parms)
380638fd1498Szrj     {
380738fd1498Szrj       for (i = 0, p = parms; i < nargs; i++, p = TREE_CHAIN (p))
380838fd1498Szrj 	{
380938fd1498Szrj 	  tree arg;
381038fd1498Szrj 	  /* If this is a varargs function defer inlining decision
381138fd1498Szrj 	     to callee.  */
381238fd1498Szrj 	  if (!p)
381338fd1498Szrj 	    break;
381438fd1498Szrj 	  arg = gimple_call_arg (stmt, i);
381538fd1498Szrj 	  if (TREE_VALUE (p) == error_mark_node
381638fd1498Szrj 	      || arg == error_mark_node
381738fd1498Szrj 	      || TREE_CODE (TREE_VALUE (p)) == VOID_TYPE
381838fd1498Szrj 	      || (!types_compatible_p (TREE_VALUE (p), TREE_TYPE (arg))
381938fd1498Szrj 		  && !fold_convertible_p (TREE_VALUE (p), arg)))
382038fd1498Szrj             return false;
382138fd1498Szrj 	}
382238fd1498Szrj     }
382338fd1498Szrj   else
382438fd1498Szrj     {
382538fd1498Szrj       if (nargs != 0)
382638fd1498Szrj         return false;
382738fd1498Szrj     }
382838fd1498Szrj   return true;
382938fd1498Szrj }
383038fd1498Szrj 
383138fd1498Szrj /* Verify if the type of the argument and lhs of CALL_STMT matches
383238fd1498Szrj    that of the function declaration CALLEE. If ARGS_COUNT_MATCH is
383338fd1498Szrj    true, the arg count needs to be the same.
383438fd1498Szrj    If we cannot verify this or there is a mismatch, return false.  */
383538fd1498Szrj 
383638fd1498Szrj bool
gimple_check_call_matching_types(gimple * call_stmt,tree callee,bool args_count_match)383738fd1498Szrj gimple_check_call_matching_types (gimple *call_stmt, tree callee,
383838fd1498Szrj 				  bool args_count_match)
383938fd1498Szrj {
384038fd1498Szrj   tree lhs;
384138fd1498Szrj 
384238fd1498Szrj   if ((DECL_RESULT (callee)
384338fd1498Szrj        && !DECL_BY_REFERENCE (DECL_RESULT (callee))
384438fd1498Szrj        && (lhs = gimple_call_lhs (call_stmt)) != NULL_TREE
384538fd1498Szrj        && !useless_type_conversion_p (TREE_TYPE (DECL_RESULT (callee)),
384638fd1498Szrj                                       TREE_TYPE (lhs))
384738fd1498Szrj        && !fold_convertible_p (TREE_TYPE (DECL_RESULT (callee)), lhs))
384838fd1498Szrj       || !gimple_check_call_args (call_stmt, callee, args_count_match))
384938fd1498Szrj     return false;
385038fd1498Szrj   return true;
385138fd1498Szrj }
385238fd1498Szrj 
385338fd1498Szrj /* Reset all state within cgraph.c so that we can rerun the compiler
385438fd1498Szrj    within the same process.  For use by toplev::finalize.  */
385538fd1498Szrj 
385638fd1498Szrj void
cgraph_c_finalize(void)385738fd1498Szrj cgraph_c_finalize (void)
385838fd1498Szrj {
385938fd1498Szrj   symtab = NULL;
386038fd1498Szrj 
386138fd1498Szrj   x_cgraph_nodes_queue = NULL;
386238fd1498Szrj 
386338fd1498Szrj   cgraph_fnver_htab = NULL;
386438fd1498Szrj   version_info_node = NULL;
386538fd1498Szrj }
386638fd1498Szrj 
386738fd1498Szrj /* A wroker for call_for_symbol_and_aliases.  */
386838fd1498Szrj 
386938fd1498Szrj bool
call_for_symbol_and_aliases_1(bool (* callback)(cgraph_node *,void *),void * data,bool include_overwritable)387038fd1498Szrj cgraph_node::call_for_symbol_and_aliases_1 (bool (*callback) (cgraph_node *,
387138fd1498Szrj 							      void *),
387238fd1498Szrj 					    void *data,
387338fd1498Szrj 					    bool include_overwritable)
387438fd1498Szrj {
387538fd1498Szrj   ipa_ref *ref;
387638fd1498Szrj   FOR_EACH_ALIAS (this, ref)
387738fd1498Szrj     {
387838fd1498Szrj       cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring);
387938fd1498Szrj       if (include_overwritable
388038fd1498Szrj 	  || alias->get_availability () > AVAIL_INTERPOSABLE)
388138fd1498Szrj 	if (alias->call_for_symbol_and_aliases (callback, data,
388238fd1498Szrj 						include_overwritable))
388338fd1498Szrj 	  return true;
388438fd1498Szrj     }
388538fd1498Szrj   return false;
388638fd1498Szrj }
388738fd1498Szrj 
388838fd1498Szrj /* Return true if NODE has thunk.  */
388938fd1498Szrj 
389038fd1498Szrj bool
has_thunk_p(cgraph_node * node,void *)389138fd1498Szrj cgraph_node::has_thunk_p (cgraph_node *node, void *)
389238fd1498Szrj {
389338fd1498Szrj   for (cgraph_edge *e = node->callers; e; e = e->next_caller)
389438fd1498Szrj     if (e->caller->thunk.thunk_p)
389538fd1498Szrj       return true;
389638fd1498Szrj   return false;
389738fd1498Szrj }
389838fd1498Szrj 
389938fd1498Szrj /* Expected frequency of executions within the function.  */
390038fd1498Szrj 
390138fd1498Szrj sreal
sreal_frequency()390238fd1498Szrj cgraph_edge::sreal_frequency ()
390338fd1498Szrj {
390438fd1498Szrj   return count.to_sreal_scale (caller->global.inlined_to
390538fd1498Szrj 			       ? caller->global.inlined_to->count
390638fd1498Szrj 			       : caller->count);
390738fd1498Szrj }
390838fd1498Szrj 
390938fd1498Szrj #include "gt-cgraph.h"
3910