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