138fd1498Szrj /* Callgraph clones
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 module provide facilities for clonning functions. I.e. creating
2238fd1498Szrj new functions based on existing functions with simple modifications,
2338fd1498Szrj such as replacement of parameters.
2438fd1498Szrj
2538fd1498Szrj To allow whole program optimization without actual presence of function
2638fd1498Szrj bodies, an additional infrastructure is provided for so-called virtual
2738fd1498Szrj clones
2838fd1498Szrj
2938fd1498Szrj A virtual clone in the callgraph is a function that has no
3038fd1498Szrj associated body, just a description of how to create its body based
3138fd1498Szrj on a different function (which itself may be a virtual clone).
3238fd1498Szrj
3338fd1498Szrj The description of function modifications includes adjustments to
3438fd1498Szrj the function's signature (which allows, for example, removing or
3538fd1498Szrj adding function arguments), substitutions to perform on the
3638fd1498Szrj function body, and, for inlined functions, a pointer to the
3738fd1498Szrj function that it will be inlined into.
3838fd1498Szrj
3938fd1498Szrj It is also possible to redirect any edge of the callgraph from a
4038fd1498Szrj function to its virtual clone. This implies updating of the call
4138fd1498Szrj site to adjust for the new function signature.
4238fd1498Szrj
4338fd1498Szrj Most of the transformations performed by inter-procedural
4438fd1498Szrj optimizations can be represented via virtual clones. For
4538fd1498Szrj instance, a constant propagation pass can produce a virtual clone
4638fd1498Szrj of the function which replaces one of its arguments by a
4738fd1498Szrj constant. The inliner can represent its decisions by producing a
4838fd1498Szrj clone of a function whose body will be later integrated into
4938fd1498Szrj a given function.
5038fd1498Szrj
5138fd1498Szrj Using virtual clones, the program can be easily updated
5238fd1498Szrj during the Execute stage, solving most of pass interactions
5338fd1498Szrj problems that would otherwise occur during Transform.
5438fd1498Szrj
5538fd1498Szrj Virtual clones are later materialized in the LTRANS stage and
5638fd1498Szrj turned into real functions. Passes executed after the virtual
5738fd1498Szrj clone were introduced also perform their Transform stage
5838fd1498Szrj on new functions, so for a pass there is no significant
5938fd1498Szrj difference between operating on a real function or a virtual
6038fd1498Szrj clone introduced before its Execute stage.
6138fd1498Szrj
6238fd1498Szrj Optimization passes then work on virtual clones introduced before
6338fd1498Szrj their Execute stage as if they were real functions. The
6438fd1498Szrj only difference is that clones are not visible during the
6538fd1498Szrj Generate Summary stage. */
6638fd1498Szrj
6738fd1498Szrj #include "config.h"
6838fd1498Szrj #include "system.h"
6938fd1498Szrj #include "coretypes.h"
7038fd1498Szrj #include "backend.h"
7138fd1498Szrj #include "target.h"
7238fd1498Szrj #include "rtl.h"
7338fd1498Szrj #include "tree.h"
7438fd1498Szrj #include "gimple.h"
7538fd1498Szrj #include "stringpool.h"
7638fd1498Szrj #include "cgraph.h"
7738fd1498Szrj #include "lto-streamer.h"
7838fd1498Szrj #include "tree-eh.h"
7938fd1498Szrj #include "tree-cfg.h"
8038fd1498Szrj #include "tree-inline.h"
8138fd1498Szrj #include "dumpfile.h"
8238fd1498Szrj #include "gimple-pretty-print.h"
8338fd1498Szrj
8438fd1498Szrj /* Create clone of edge in the node N represented by CALL_EXPR
8538fd1498Szrj the callgraph. */
8638fd1498Szrj
8738fd1498Szrj cgraph_edge *
clone(cgraph_node * n,gcall * call_stmt,unsigned stmt_uid,profile_count num,profile_count den,bool update_original)8838fd1498Szrj cgraph_edge::clone (cgraph_node *n, gcall *call_stmt, unsigned stmt_uid,
8938fd1498Szrj profile_count num, profile_count den,
9038fd1498Szrj bool update_original)
9138fd1498Szrj {
9238fd1498Szrj cgraph_edge *new_edge;
9338fd1498Szrj profile_count::adjust_for_ipa_scaling (&num, &den);
9438fd1498Szrj profile_count prof_count = count.apply_scale (num, den);
9538fd1498Szrj
9638fd1498Szrj if (indirect_unknown_callee)
9738fd1498Szrj {
9838fd1498Szrj tree decl;
9938fd1498Szrj
10038fd1498Szrj if (call_stmt && (decl = gimple_call_fndecl (call_stmt))
10138fd1498Szrj /* When the call is speculative, we need to resolve it
10238fd1498Szrj via cgraph_resolve_speculation and not here. */
10338fd1498Szrj && !speculative)
10438fd1498Szrj {
10538fd1498Szrj cgraph_node *callee = cgraph_node::get (decl);
10638fd1498Szrj gcc_checking_assert (callee);
10738fd1498Szrj new_edge = n->create_edge (callee, call_stmt, prof_count);
10838fd1498Szrj }
10938fd1498Szrj else
11038fd1498Szrj {
11138fd1498Szrj new_edge = n->create_indirect_edge (call_stmt,
11238fd1498Szrj indirect_info->ecf_flags,
11338fd1498Szrj prof_count, false);
11438fd1498Szrj *new_edge->indirect_info = *indirect_info;
11538fd1498Szrj }
11638fd1498Szrj }
11738fd1498Szrj else
11838fd1498Szrj {
11938fd1498Szrj new_edge = n->create_edge (callee, call_stmt, prof_count);
12038fd1498Szrj if (indirect_info)
12138fd1498Szrj {
12238fd1498Szrj new_edge->indirect_info
12338fd1498Szrj = ggc_cleared_alloc<cgraph_indirect_call_info> ();
12438fd1498Szrj *new_edge->indirect_info = *indirect_info;
12538fd1498Szrj }
12638fd1498Szrj }
12738fd1498Szrj
12838fd1498Szrj new_edge->inline_failed = inline_failed;
12938fd1498Szrj new_edge->indirect_inlining_edge = indirect_inlining_edge;
13038fd1498Szrj new_edge->lto_stmt_uid = stmt_uid;
13138fd1498Szrj /* Clone flags that depend on call_stmt availability manually. */
13238fd1498Szrj new_edge->can_throw_external = can_throw_external;
13338fd1498Szrj new_edge->call_stmt_cannot_inline_p = call_stmt_cannot_inline_p;
13438fd1498Szrj new_edge->speculative = speculative;
13538fd1498Szrj new_edge->in_polymorphic_cdtor = in_polymorphic_cdtor;
13638fd1498Szrj
13738fd1498Szrj /* Update IPA profile. Local profiles need no updating in original. */
13838fd1498Szrj if (update_original)
13938fd1498Szrj count = count.combine_with_ipa_count (count.ipa ()
14038fd1498Szrj - new_edge->count.ipa ());
14138fd1498Szrj symtab->call_edge_duplication_hooks (this, new_edge);
14238fd1498Szrj return new_edge;
14338fd1498Szrj }
14438fd1498Szrj
14538fd1498Szrj /* Build variant of function type ORIG_TYPE skipping ARGS_TO_SKIP and the
14638fd1498Szrj return value if SKIP_RETURN is true. */
14738fd1498Szrj
14838fd1498Szrj tree
cgraph_build_function_type_skip_args(tree orig_type,bitmap args_to_skip,bool skip_return)14938fd1498Szrj cgraph_build_function_type_skip_args (tree orig_type, bitmap args_to_skip,
15038fd1498Szrj bool skip_return)
15138fd1498Szrj {
15238fd1498Szrj tree new_type = NULL;
15338fd1498Szrj tree args, new_args = NULL;
15438fd1498Szrj tree new_reversed;
15538fd1498Szrj int i = 0;
15638fd1498Szrj
15738fd1498Szrj for (args = TYPE_ARG_TYPES (orig_type); args && args != void_list_node;
15838fd1498Szrj args = TREE_CHAIN (args), i++)
15938fd1498Szrj if (!args_to_skip || !bitmap_bit_p (args_to_skip, i))
16038fd1498Szrj new_args = tree_cons (NULL_TREE, TREE_VALUE (args), new_args);
16138fd1498Szrj
16238fd1498Szrj new_reversed = nreverse (new_args);
16338fd1498Szrj if (args)
16438fd1498Szrj {
16538fd1498Szrj if (new_reversed)
16638fd1498Szrj TREE_CHAIN (new_args) = void_list_node;
16738fd1498Szrj else
16838fd1498Szrj new_reversed = void_list_node;
16938fd1498Szrj }
17038fd1498Szrj
17138fd1498Szrj /* Use copy_node to preserve as much as possible from original type
17238fd1498Szrj (debug info, attribute lists etc.)
17338fd1498Szrj Exception is METHOD_TYPEs must have THIS argument.
17438fd1498Szrj When we are asked to remove it, we need to build new FUNCTION_TYPE
17538fd1498Szrj instead. */
17638fd1498Szrj if (TREE_CODE (orig_type) != METHOD_TYPE
17738fd1498Szrj || !args_to_skip
17838fd1498Szrj || !bitmap_bit_p (args_to_skip, 0))
17938fd1498Szrj {
18038fd1498Szrj new_type = build_distinct_type_copy (orig_type);
18138fd1498Szrj TYPE_ARG_TYPES (new_type) = new_reversed;
18238fd1498Szrj }
18338fd1498Szrj else
18438fd1498Szrj {
18538fd1498Szrj new_type
18638fd1498Szrj = build_distinct_type_copy (build_function_type (TREE_TYPE (orig_type),
18738fd1498Szrj new_reversed));
18838fd1498Szrj TYPE_CONTEXT (new_type) = TYPE_CONTEXT (orig_type);
18938fd1498Szrj }
19038fd1498Szrj
19138fd1498Szrj if (skip_return)
19238fd1498Szrj TREE_TYPE (new_type) = void_type_node;
19338fd1498Szrj
19438fd1498Szrj return new_type;
19538fd1498Szrj }
19638fd1498Szrj
19738fd1498Szrj /* Build variant of function decl ORIG_DECL skipping ARGS_TO_SKIP and the
19838fd1498Szrj return value if SKIP_RETURN is true.
19938fd1498Szrj
20038fd1498Szrj Arguments from DECL_ARGUMENTS list can't be removed now, since they are
20138fd1498Szrj linked by TREE_CHAIN directly. The caller is responsible for eliminating
20238fd1498Szrj them when they are being duplicated (i.e. copy_arguments_for_versioning). */
20338fd1498Szrj
20438fd1498Szrj static tree
build_function_decl_skip_args(tree orig_decl,bitmap args_to_skip,bool skip_return)20538fd1498Szrj build_function_decl_skip_args (tree orig_decl, bitmap args_to_skip,
20638fd1498Szrj bool skip_return)
20738fd1498Szrj {
20838fd1498Szrj tree new_decl = copy_node (orig_decl);
20938fd1498Szrj tree new_type;
21038fd1498Szrj
21138fd1498Szrj new_type = TREE_TYPE (orig_decl);
21238fd1498Szrj if (prototype_p (new_type)
21338fd1498Szrj || (skip_return && !VOID_TYPE_P (TREE_TYPE (new_type))))
21438fd1498Szrj new_type
21538fd1498Szrj = cgraph_build_function_type_skip_args (new_type, args_to_skip,
21638fd1498Szrj skip_return);
21738fd1498Szrj TREE_TYPE (new_decl) = new_type;
21838fd1498Szrj
21938fd1498Szrj /* For declarations setting DECL_VINDEX (i.e. methods)
22038fd1498Szrj we expect first argument to be THIS pointer. */
22138fd1498Szrj if (args_to_skip && bitmap_bit_p (args_to_skip, 0))
22238fd1498Szrj DECL_VINDEX (new_decl) = NULL_TREE;
22338fd1498Szrj
22438fd1498Szrj /* When signature changes, we need to clear builtin info. */
22538fd1498Szrj if (DECL_BUILT_IN (new_decl)
22638fd1498Szrj && args_to_skip
22738fd1498Szrj && !bitmap_empty_p (args_to_skip))
22838fd1498Szrj {
22938fd1498Szrj DECL_BUILT_IN_CLASS (new_decl) = NOT_BUILT_IN;
23038fd1498Szrj DECL_FUNCTION_CODE (new_decl) = (enum built_in_function) 0;
23138fd1498Szrj }
23238fd1498Szrj /* The FE might have information and assumptions about the other
23338fd1498Szrj arguments. */
23438fd1498Szrj DECL_LANG_SPECIFIC (new_decl) = NULL;
23538fd1498Szrj return new_decl;
23638fd1498Szrj }
23738fd1498Szrj
23838fd1498Szrj /* Set flags of NEW_NODE and its decl. NEW_NODE is a newly created private
23938fd1498Szrj clone or its thunk. */
24038fd1498Szrj
24138fd1498Szrj static void
set_new_clone_decl_and_node_flags(cgraph_node * new_node)24238fd1498Szrj set_new_clone_decl_and_node_flags (cgraph_node *new_node)
24338fd1498Szrj {
24438fd1498Szrj DECL_EXTERNAL (new_node->decl) = 0;
24538fd1498Szrj TREE_PUBLIC (new_node->decl) = 0;
24638fd1498Szrj DECL_COMDAT (new_node->decl) = 0;
24738fd1498Szrj DECL_WEAK (new_node->decl) = 0;
24838fd1498Szrj DECL_VIRTUAL_P (new_node->decl) = 0;
24938fd1498Szrj DECL_STATIC_CONSTRUCTOR (new_node->decl) = 0;
25038fd1498Szrj DECL_STATIC_DESTRUCTOR (new_node->decl) = 0;
25138fd1498Szrj
25238fd1498Szrj new_node->externally_visible = 0;
25338fd1498Szrj new_node->local.local = 1;
25438fd1498Szrj new_node->lowered = true;
25538fd1498Szrj }
25638fd1498Szrj
25738fd1498Szrj /* Duplicate thunk THUNK if necessary but make it to refer to NODE.
25838fd1498Szrj ARGS_TO_SKIP, if non-NULL, determines which parameters should be omitted.
25938fd1498Szrj Function can return NODE if no thunk is necessary, which can happen when
26038fd1498Szrj thunk is this_adjusting but we are removing this parameter. */
26138fd1498Szrj
26238fd1498Szrj static cgraph_node *
duplicate_thunk_for_node(cgraph_node * thunk,cgraph_node * node)26338fd1498Szrj duplicate_thunk_for_node (cgraph_node *thunk, cgraph_node *node)
26438fd1498Szrj {
26538fd1498Szrj cgraph_node *new_thunk, *thunk_of;
26638fd1498Szrj thunk_of = thunk->callees->callee->ultimate_alias_target ();
26738fd1498Szrj
26838fd1498Szrj if (thunk_of->thunk.thunk_p)
26938fd1498Szrj node = duplicate_thunk_for_node (thunk_of, node);
27038fd1498Szrj
27138fd1498Szrj if (!DECL_ARGUMENTS (thunk->decl))
27238fd1498Szrj thunk->get_untransformed_body ();
27338fd1498Szrj
27438fd1498Szrj cgraph_edge *cs;
27538fd1498Szrj for (cs = node->callers; cs; cs = cs->next_caller)
27638fd1498Szrj if (cs->caller->thunk.thunk_p
27738fd1498Szrj && cs->caller->thunk.this_adjusting == thunk->thunk.this_adjusting
27838fd1498Szrj && cs->caller->thunk.fixed_offset == thunk->thunk.fixed_offset
27938fd1498Szrj && cs->caller->thunk.virtual_offset_p == thunk->thunk.virtual_offset_p
28038fd1498Szrj && cs->caller->thunk.virtual_value == thunk->thunk.virtual_value)
28138fd1498Szrj return cs->caller;
28238fd1498Szrj
28338fd1498Szrj tree new_decl;
28438fd1498Szrj if (!node->clone.args_to_skip)
28538fd1498Szrj new_decl = copy_node (thunk->decl);
28638fd1498Szrj else
28738fd1498Szrj {
28838fd1498Szrj /* We do not need to duplicate this_adjusting thunks if we have removed
28938fd1498Szrj this. */
29038fd1498Szrj if (thunk->thunk.this_adjusting
29138fd1498Szrj && bitmap_bit_p (node->clone.args_to_skip, 0))
29238fd1498Szrj return node;
29338fd1498Szrj
29438fd1498Szrj new_decl = build_function_decl_skip_args (thunk->decl,
29538fd1498Szrj node->clone.args_to_skip,
29638fd1498Szrj false);
29738fd1498Szrj }
29838fd1498Szrj
29938fd1498Szrj tree *link = &DECL_ARGUMENTS (new_decl);
30038fd1498Szrj int i = 0;
30138fd1498Szrj for (tree pd = DECL_ARGUMENTS (thunk->decl); pd; pd = DECL_CHAIN (pd), i++)
30238fd1498Szrj {
30338fd1498Szrj if (!node->clone.args_to_skip
30438fd1498Szrj || !bitmap_bit_p (node->clone.args_to_skip, i))
30538fd1498Szrj {
30638fd1498Szrj tree nd = copy_node (pd);
30738fd1498Szrj DECL_CONTEXT (nd) = new_decl;
30838fd1498Szrj *link = nd;
30938fd1498Szrj link = &DECL_CHAIN (nd);
31038fd1498Szrj }
31138fd1498Szrj }
31238fd1498Szrj *link = NULL_TREE;
31338fd1498Szrj
31438fd1498Szrj gcc_checking_assert (!DECL_STRUCT_FUNCTION (new_decl));
31538fd1498Szrj gcc_checking_assert (!DECL_INITIAL (new_decl));
31638fd1498Szrj gcc_checking_assert (!DECL_RESULT (new_decl));
31738fd1498Szrj gcc_checking_assert (!DECL_RTL_SET_P (new_decl));
31838fd1498Szrj
31938fd1498Szrj DECL_NAME (new_decl) = clone_function_name (thunk->decl, "artificial_thunk");
32038fd1498Szrj SET_DECL_ASSEMBLER_NAME (new_decl, DECL_NAME (new_decl));
32138fd1498Szrj
32238fd1498Szrj new_thunk = cgraph_node::create (new_decl);
32338fd1498Szrj set_new_clone_decl_and_node_flags (new_thunk);
32438fd1498Szrj new_thunk->definition = true;
32538fd1498Szrj new_thunk->local.can_change_signature = node->local.can_change_signature;
32638fd1498Szrj new_thunk->thunk = thunk->thunk;
32738fd1498Szrj new_thunk->unique_name = in_lto_p;
32838fd1498Szrj new_thunk->former_clone_of = thunk->decl;
32938fd1498Szrj new_thunk->clone.args_to_skip = node->clone.args_to_skip;
33038fd1498Szrj new_thunk->clone.combined_args_to_skip = node->clone.combined_args_to_skip;
33138fd1498Szrj
33238fd1498Szrj cgraph_edge *e = new_thunk->create_edge (node, NULL, new_thunk->count);
33338fd1498Szrj symtab->call_edge_duplication_hooks (thunk->callees, e);
33438fd1498Szrj symtab->call_cgraph_duplication_hooks (thunk, new_thunk);
33538fd1498Szrj return new_thunk;
33638fd1498Szrj }
33738fd1498Szrj
33838fd1498Szrj /* If E does not lead to a thunk, simply redirect it to N. Otherwise create
33938fd1498Szrj one or more equivalent thunks for N and redirect E to the first in the
34038fd1498Szrj chain. Note that it is then necessary to call
34138fd1498Szrj n->expand_all_artificial_thunks once all callers are redirected. */
34238fd1498Szrj
34338fd1498Szrj void
redirect_callee_duplicating_thunks(cgraph_node * n)34438fd1498Szrj cgraph_edge::redirect_callee_duplicating_thunks (cgraph_node *n)
34538fd1498Szrj {
34638fd1498Szrj cgraph_node *orig_to = callee->ultimate_alias_target ();
34738fd1498Szrj if (orig_to->thunk.thunk_p)
34838fd1498Szrj n = duplicate_thunk_for_node (orig_to, n);
34938fd1498Szrj
35038fd1498Szrj redirect_callee (n);
35138fd1498Szrj }
35238fd1498Szrj
35338fd1498Szrj /* Call expand_thunk on all callers that are thunks and if analyze those nodes
35438fd1498Szrj that were expanded. */
35538fd1498Szrj
35638fd1498Szrj void
expand_all_artificial_thunks()35738fd1498Szrj cgraph_node::expand_all_artificial_thunks ()
35838fd1498Szrj {
35938fd1498Szrj cgraph_edge *e;
36038fd1498Szrj for (e = callers; e;)
36138fd1498Szrj if (e->caller->thunk.thunk_p)
36238fd1498Szrj {
36338fd1498Szrj cgraph_node *thunk = e->caller;
36438fd1498Szrj
36538fd1498Szrj e = e->next_caller;
36638fd1498Szrj if (thunk->expand_thunk (false, false))
36738fd1498Szrj {
36838fd1498Szrj thunk->thunk.thunk_p = false;
36938fd1498Szrj thunk->analyze ();
37038fd1498Szrj }
37138fd1498Szrj thunk->expand_all_artificial_thunks ();
37238fd1498Szrj }
37338fd1498Szrj else
37438fd1498Szrj e = e->next_caller;
37538fd1498Szrj }
37638fd1498Szrj
37738fd1498Szrj void
dump_callgraph_transformation(const cgraph_node * original,const cgraph_node * clone,const char * suffix)37838fd1498Szrj dump_callgraph_transformation (const cgraph_node *original,
37938fd1498Szrj const cgraph_node *clone,
38038fd1498Szrj const char *suffix)
38138fd1498Szrj {
38238fd1498Szrj if (symtab->ipa_clones_dump_file)
38338fd1498Szrj {
38438fd1498Szrj fprintf (symtab->ipa_clones_dump_file,
38538fd1498Szrj "Callgraph clone;%s;%d;%s;%d;%d;%s;%d;%s;%d;%d;%s\n",
38638fd1498Szrj original->asm_name (), original->order,
38738fd1498Szrj DECL_SOURCE_FILE (original->decl),
38838fd1498Szrj DECL_SOURCE_LINE (original->decl),
38938fd1498Szrj DECL_SOURCE_COLUMN (original->decl), clone->asm_name (),
39038fd1498Szrj clone->order, DECL_SOURCE_FILE (clone->decl),
39138fd1498Szrj DECL_SOURCE_LINE (clone->decl), DECL_SOURCE_COLUMN (clone->decl),
39238fd1498Szrj suffix);
39338fd1498Szrj
39438fd1498Szrj symtab->cloned_nodes.add (original);
39538fd1498Szrj symtab->cloned_nodes.add (clone);
39638fd1498Szrj }
39738fd1498Szrj }
39838fd1498Szrj
39938fd1498Szrj /* Create node representing clone of N executed COUNT times. Decrease
40038fd1498Szrj the execution counts from original node too.
40138fd1498Szrj The new clone will have decl set to DECL that may or may not be the same
40238fd1498Szrj as decl of N.
40338fd1498Szrj
40438fd1498Szrj When UPDATE_ORIGINAL is true, the counts are subtracted from the original
40538fd1498Szrj function's profile to reflect the fact that part of execution is handled
40638fd1498Szrj by node.
40738fd1498Szrj When CALL_DUPLICATOIN_HOOK is true, the ipa passes are acknowledged about
40838fd1498Szrj the new clone. Otherwise the caller is responsible for doing so later.
40938fd1498Szrj
41038fd1498Szrj If the new node is being inlined into another one, NEW_INLINED_TO should be
41138fd1498Szrj the outline function the new one is (even indirectly) inlined to. All hooks
41238fd1498Szrj will see this in node's global.inlined_to, when invoked. Can be NULL if the
41338fd1498Szrj node is not inlined. */
41438fd1498Szrj
41538fd1498Szrj cgraph_node *
create_clone(tree new_decl,profile_count prof_count,bool update_original,vec<cgraph_edge * > redirect_callers,bool call_duplication_hook,cgraph_node * new_inlined_to,bitmap args_to_skip,const char * suffix)41638fd1498Szrj cgraph_node::create_clone (tree new_decl, profile_count prof_count,
41738fd1498Szrj bool update_original,
41838fd1498Szrj vec<cgraph_edge *> redirect_callers,
41938fd1498Szrj bool call_duplication_hook,
42038fd1498Szrj cgraph_node *new_inlined_to,
42138fd1498Szrj bitmap args_to_skip, const char *suffix)
42238fd1498Szrj {
42338fd1498Szrj cgraph_node *new_node = symtab->create_empty ();
42438fd1498Szrj cgraph_edge *e;
42538fd1498Szrj unsigned i;
42638fd1498Szrj profile_count old_count = count;
42738fd1498Szrj
42838fd1498Szrj if (new_inlined_to)
42938fd1498Szrj dump_callgraph_transformation (this, new_inlined_to, "inlining to");
43038fd1498Szrj
43138fd1498Szrj /* When inlining we scale precisely to prof_count, when cloning we can
43238fd1498Szrj preserve local profile. */
43338fd1498Szrj if (!new_inlined_to)
43438fd1498Szrj prof_count = count.combine_with_ipa_count (prof_count);
43538fd1498Szrj new_node->count = prof_count;
43638fd1498Szrj
43738fd1498Szrj /* Update IPA profile. Local profiles need no updating in original. */
43838fd1498Szrj if (update_original)
43938fd1498Szrj count = count.combine_with_ipa_count (count.ipa () - prof_count.ipa ());
44038fd1498Szrj new_node->decl = new_decl;
44138fd1498Szrj new_node->register_symbol ();
44238fd1498Szrj new_node->origin = origin;
44338fd1498Szrj new_node->lto_file_data = lto_file_data;
44438fd1498Szrj if (new_node->origin)
44538fd1498Szrj {
44638fd1498Szrj new_node->next_nested = new_node->origin->nested;
44738fd1498Szrj new_node->origin->nested = new_node;
44838fd1498Szrj }
44938fd1498Szrj new_node->analyzed = analyzed;
45038fd1498Szrj new_node->definition = definition;
45138fd1498Szrj new_node->local = local;
45238fd1498Szrj new_node->externally_visible = false;
45338fd1498Szrj new_node->no_reorder = no_reorder;
45438fd1498Szrj new_node->local.local = true;
45538fd1498Szrj new_node->global = global;
45638fd1498Szrj new_node->global.inlined_to = new_inlined_to;
45738fd1498Szrj new_node->rtl = rtl;
45838fd1498Szrj new_node->frequency = frequency;
45938fd1498Szrj new_node->tp_first_run = tp_first_run;
46038fd1498Szrj new_node->tm_clone = tm_clone;
46138fd1498Szrj new_node->icf_merged = icf_merged;
46238fd1498Szrj new_node->merged_comdat = merged_comdat;
46338fd1498Szrj new_node->thunk = thunk;
46438fd1498Szrj
46538fd1498Szrj new_node->clone.tree_map = NULL;
46638fd1498Szrj new_node->clone.args_to_skip = args_to_skip;
46738fd1498Szrj new_node->split_part = split_part;
46838fd1498Szrj if (!args_to_skip)
46938fd1498Szrj new_node->clone.combined_args_to_skip = clone.combined_args_to_skip;
47038fd1498Szrj else if (clone.combined_args_to_skip)
47138fd1498Szrj {
47238fd1498Szrj new_node->clone.combined_args_to_skip = BITMAP_GGC_ALLOC ();
47338fd1498Szrj bitmap_ior (new_node->clone.combined_args_to_skip,
47438fd1498Szrj clone.combined_args_to_skip, args_to_skip);
47538fd1498Szrj }
47638fd1498Szrj else
47738fd1498Szrj new_node->clone.combined_args_to_skip = args_to_skip;
47838fd1498Szrj
47938fd1498Szrj FOR_EACH_VEC_ELT (redirect_callers, i, e)
48038fd1498Szrj {
48138fd1498Szrj /* Redirect calls to the old version node to point to its new
48238fd1498Szrj version. The only exception is when the edge was proved to
48338fd1498Szrj be unreachable during the clonning procedure. */
48438fd1498Szrj if (!e->callee
48538fd1498Szrj || DECL_BUILT_IN_CLASS (e->callee->decl) != BUILT_IN_NORMAL
48638fd1498Szrj || DECL_FUNCTION_CODE (e->callee->decl) != BUILT_IN_UNREACHABLE)
48738fd1498Szrj e->redirect_callee_duplicating_thunks (new_node);
48838fd1498Szrj }
48938fd1498Szrj new_node->expand_all_artificial_thunks ();
49038fd1498Szrj
49138fd1498Szrj for (e = callees;e; e=e->next_callee)
49238fd1498Szrj e->clone (new_node, e->call_stmt, e->lto_stmt_uid, new_node->count, old_count,
49338fd1498Szrj update_original);
49438fd1498Szrj
49538fd1498Szrj for (e = indirect_calls; e; e = e->next_callee)
49638fd1498Szrj e->clone (new_node, e->call_stmt, e->lto_stmt_uid,
49738fd1498Szrj new_node->count, old_count, update_original);
49838fd1498Szrj new_node->clone_references (this);
49938fd1498Szrj
50038fd1498Szrj new_node->next_sibling_clone = clones;
50138fd1498Szrj if (clones)
50238fd1498Szrj clones->prev_sibling_clone = new_node;
50338fd1498Szrj clones = new_node;
50438fd1498Szrj new_node->clone_of = this;
50538fd1498Szrj
50638fd1498Szrj if (call_duplication_hook)
50738fd1498Szrj symtab->call_cgraph_duplication_hooks (this, new_node);
50838fd1498Szrj
50938fd1498Szrj if (!new_inlined_to)
51038fd1498Szrj dump_callgraph_transformation (this, new_node, suffix);
51138fd1498Szrj
51238fd1498Szrj return new_node;
51338fd1498Szrj }
51438fd1498Szrj
51538fd1498Szrj static GTY(()) unsigned int clone_fn_id_num;
51638fd1498Szrj
51738fd1498Szrj /* Return a new assembler name for a clone with SUFFIX of a decl named
51838fd1498Szrj NAME. */
51938fd1498Szrj
52038fd1498Szrj tree
clone_function_name_1(const char * name,const char * suffix)52138fd1498Szrj clone_function_name_1 (const char *name, const char *suffix)
52238fd1498Szrj {
52338fd1498Szrj size_t len = strlen (name);
52438fd1498Szrj char *tmp_name, *prefix;
52538fd1498Szrj
52638fd1498Szrj prefix = XALLOCAVEC (char, len + strlen (suffix) + 2);
52738fd1498Szrj memcpy (prefix, name, len);
52838fd1498Szrj strcpy (prefix + len + 1, suffix);
52938fd1498Szrj prefix[len] = symbol_table::symbol_suffix_separator ();
53038fd1498Szrj ASM_FORMAT_PRIVATE_NAME (tmp_name, prefix, clone_fn_id_num++);
53138fd1498Szrj return get_identifier (tmp_name);
53238fd1498Szrj }
53338fd1498Szrj
53438fd1498Szrj /* Return a new assembler name for a clone of DECL with SUFFIX. */
53538fd1498Szrj
53638fd1498Szrj tree
clone_function_name(tree decl,const char * suffix)53738fd1498Szrj clone_function_name (tree decl, const char *suffix)
53838fd1498Szrj {
53938fd1498Szrj tree name = DECL_ASSEMBLER_NAME (decl);
54038fd1498Szrj return clone_function_name_1 (IDENTIFIER_POINTER (name), suffix);
54138fd1498Szrj }
54238fd1498Szrj
54338fd1498Szrj
54438fd1498Szrj /* Create callgraph node clone with new declaration. The actual body will
54538fd1498Szrj be copied later at compilation stage.
54638fd1498Szrj
54738fd1498Szrj TODO: after merging in ipa-sra use function call notes instead of args_to_skip
54838fd1498Szrj bitmap interface.
54938fd1498Szrj */
55038fd1498Szrj cgraph_node *
create_virtual_clone(vec<cgraph_edge * > redirect_callers,vec<ipa_replace_map *,va_gc> * tree_map,bitmap args_to_skip,const char * suffix)55138fd1498Szrj cgraph_node::create_virtual_clone (vec<cgraph_edge *> redirect_callers,
55238fd1498Szrj vec<ipa_replace_map *, va_gc> *tree_map,
55338fd1498Szrj bitmap args_to_skip, const char * suffix)
55438fd1498Szrj {
55538fd1498Szrj tree old_decl = decl;
55638fd1498Szrj cgraph_node *new_node = NULL;
55738fd1498Szrj tree new_decl;
55838fd1498Szrj size_t len, i;
55938fd1498Szrj ipa_replace_map *map;
56038fd1498Szrj char *name;
56138fd1498Szrj
56238fd1498Szrj gcc_checking_assert (local.versionable);
56338fd1498Szrj gcc_assert (local.can_change_signature || !args_to_skip);
56438fd1498Szrj
56538fd1498Szrj /* Make a new FUNCTION_DECL tree node */
56638fd1498Szrj if (!args_to_skip)
56738fd1498Szrj new_decl = copy_node (old_decl);
56838fd1498Szrj else
56938fd1498Szrj new_decl = build_function_decl_skip_args (old_decl, args_to_skip, false);
57038fd1498Szrj
57138fd1498Szrj /* These pointers represent function body and will be populated only when clone
57238fd1498Szrj is materialized. */
57338fd1498Szrj gcc_assert (new_decl != old_decl);
57438fd1498Szrj DECL_STRUCT_FUNCTION (new_decl) = NULL;
57538fd1498Szrj DECL_ARGUMENTS (new_decl) = NULL;
57638fd1498Szrj DECL_INITIAL (new_decl) = NULL;
57738fd1498Szrj DECL_RESULT (new_decl) = NULL;
57838fd1498Szrj /* We can not do DECL_RESULT (new_decl) = NULL; here because of LTO partitioning
57938fd1498Szrj sometimes storing only clone decl instead of original. */
58038fd1498Szrj
58138fd1498Szrj /* Generate a new name for the new version. */
58238fd1498Szrj len = IDENTIFIER_LENGTH (DECL_NAME (old_decl));
58338fd1498Szrj name = XALLOCAVEC (char, len + strlen (suffix) + 2);
58438fd1498Szrj memcpy (name, IDENTIFIER_POINTER (DECL_NAME (old_decl)), len);
58538fd1498Szrj strcpy (name + len + 1, suffix);
58638fd1498Szrj name[len] = '.';
58738fd1498Szrj DECL_NAME (new_decl) = get_identifier (name);
58838fd1498Szrj SET_DECL_ASSEMBLER_NAME (new_decl, clone_function_name (old_decl, suffix));
58938fd1498Szrj SET_DECL_RTL (new_decl, NULL);
59038fd1498Szrj
59138fd1498Szrj new_node = create_clone (new_decl, count, false,
59238fd1498Szrj redirect_callers, false, NULL, args_to_skip, suffix);
59338fd1498Szrj
59438fd1498Szrj /* Update the properties.
59538fd1498Szrj Make clone visible only within this translation unit. Make sure
59638fd1498Szrj that is not weak also.
59738fd1498Szrj ??? We cannot use COMDAT linkage because there is no
59838fd1498Szrj ABI support for this. */
59938fd1498Szrj set_new_clone_decl_and_node_flags (new_node);
60038fd1498Szrj new_node->clone.tree_map = tree_map;
60138fd1498Szrj if (!implicit_section)
60238fd1498Szrj new_node->set_section (get_section ());
60338fd1498Szrj
60438fd1498Szrj /* Clones of global symbols or symbols with unique names are unique. */
60538fd1498Szrj if ((TREE_PUBLIC (old_decl)
60638fd1498Szrj && !DECL_EXTERNAL (old_decl)
60738fd1498Szrj && !DECL_WEAK (old_decl)
60838fd1498Szrj && !DECL_COMDAT (old_decl))
60938fd1498Szrj || in_lto_p)
61038fd1498Szrj new_node->unique_name = true;
61138fd1498Szrj FOR_EACH_VEC_SAFE_ELT (tree_map, i, map)
61238fd1498Szrj new_node->maybe_create_reference (map->new_tree, NULL);
61338fd1498Szrj
61438fd1498Szrj if (ipa_transforms_to_apply.exists ())
61538fd1498Szrj new_node->ipa_transforms_to_apply
61638fd1498Szrj = ipa_transforms_to_apply.copy ();
61738fd1498Szrj
61838fd1498Szrj symtab->call_cgraph_duplication_hooks (this, new_node);
61938fd1498Szrj
62038fd1498Szrj return new_node;
62138fd1498Szrj }
62238fd1498Szrj
62338fd1498Szrj /* callgraph node being removed from symbol table; see if its entry can be
62438fd1498Szrj replaced by other inline clone. */
62538fd1498Szrj cgraph_node *
find_replacement(void)62638fd1498Szrj cgraph_node::find_replacement (void)
62738fd1498Szrj {
62838fd1498Szrj cgraph_node *next_inline_clone, *replacement;
62938fd1498Szrj
63038fd1498Szrj for (next_inline_clone = clones;
63138fd1498Szrj next_inline_clone
63238fd1498Szrj && next_inline_clone->decl != decl;
63338fd1498Szrj next_inline_clone = next_inline_clone->next_sibling_clone)
63438fd1498Szrj ;
63538fd1498Szrj
63638fd1498Szrj /* If there is inline clone of the node being removed, we need
63738fd1498Szrj to put it into the position of removed node and reorganize all
63838fd1498Szrj other clones to be based on it. */
63938fd1498Szrj if (next_inline_clone)
64038fd1498Szrj {
64138fd1498Szrj cgraph_node *n;
64238fd1498Szrj cgraph_node *new_clones;
64338fd1498Szrj
64438fd1498Szrj replacement = next_inline_clone;
64538fd1498Szrj
64638fd1498Szrj /* Unlink inline clone from the list of clones of removed node. */
64738fd1498Szrj if (next_inline_clone->next_sibling_clone)
64838fd1498Szrj next_inline_clone->next_sibling_clone->prev_sibling_clone
64938fd1498Szrj = next_inline_clone->prev_sibling_clone;
65038fd1498Szrj if (next_inline_clone->prev_sibling_clone)
65138fd1498Szrj {
65238fd1498Szrj gcc_assert (clones != next_inline_clone);
65338fd1498Szrj next_inline_clone->prev_sibling_clone->next_sibling_clone
65438fd1498Szrj = next_inline_clone->next_sibling_clone;
65538fd1498Szrj }
65638fd1498Szrj else
65738fd1498Szrj {
65838fd1498Szrj gcc_assert (clones == next_inline_clone);
65938fd1498Szrj clones = next_inline_clone->next_sibling_clone;
66038fd1498Szrj }
66138fd1498Szrj
66238fd1498Szrj new_clones = clones;
66338fd1498Szrj clones = NULL;
66438fd1498Szrj
66538fd1498Szrj /* Copy clone info. */
66638fd1498Szrj next_inline_clone->clone = clone;
66738fd1498Szrj
66838fd1498Szrj /* Now place it into clone tree at same level at NODE. */
66938fd1498Szrj next_inline_clone->clone_of = clone_of;
67038fd1498Szrj next_inline_clone->prev_sibling_clone = NULL;
67138fd1498Szrj next_inline_clone->next_sibling_clone = NULL;
67238fd1498Szrj if (clone_of)
67338fd1498Szrj {
67438fd1498Szrj if (clone_of->clones)
67538fd1498Szrj clone_of->clones->prev_sibling_clone = next_inline_clone;
67638fd1498Szrj next_inline_clone->next_sibling_clone = clone_of->clones;
67738fd1498Szrj clone_of->clones = next_inline_clone;
67838fd1498Szrj }
67938fd1498Szrj
68038fd1498Szrj /* Merge the clone list. */
68138fd1498Szrj if (new_clones)
68238fd1498Szrj {
68338fd1498Szrj if (!next_inline_clone->clones)
68438fd1498Szrj next_inline_clone->clones = new_clones;
68538fd1498Szrj else
68638fd1498Szrj {
68738fd1498Szrj n = next_inline_clone->clones;
68838fd1498Szrj while (n->next_sibling_clone)
68938fd1498Szrj n = n->next_sibling_clone;
69038fd1498Szrj n->next_sibling_clone = new_clones;
69138fd1498Szrj new_clones->prev_sibling_clone = n;
69238fd1498Szrj }
69338fd1498Szrj }
69438fd1498Szrj
69538fd1498Szrj /* Update clone_of pointers. */
69638fd1498Szrj n = new_clones;
69738fd1498Szrj while (n)
69838fd1498Szrj {
69938fd1498Szrj n->clone_of = next_inline_clone;
70038fd1498Szrj n = n->next_sibling_clone;
70138fd1498Szrj }
70238fd1498Szrj return replacement;
70338fd1498Szrj }
70438fd1498Szrj else
70538fd1498Szrj return NULL;
70638fd1498Szrj }
70738fd1498Szrj
70838fd1498Szrj /* Like cgraph_set_call_stmt but walk the clone tree and update all
70938fd1498Szrj clones sharing the same function body.
71038fd1498Szrj When WHOLE_SPECULATIVE_EDGES is true, all three components of
71138fd1498Szrj speculative edge gets updated. Otherwise we update only direct
71238fd1498Szrj call. */
71338fd1498Szrj
71438fd1498Szrj void
set_call_stmt_including_clones(gimple * old_stmt,gcall * new_stmt,bool update_speculative)71538fd1498Szrj cgraph_node::set_call_stmt_including_clones (gimple *old_stmt,
71638fd1498Szrj gcall *new_stmt,
71738fd1498Szrj bool update_speculative)
71838fd1498Szrj {
71938fd1498Szrj cgraph_node *node;
72038fd1498Szrj cgraph_edge *edge = get_edge (old_stmt);
72138fd1498Szrj
72238fd1498Szrj if (edge)
72338fd1498Szrj edge->set_call_stmt (new_stmt, update_speculative);
72438fd1498Szrj
72538fd1498Szrj node = clones;
72638fd1498Szrj if (node)
72738fd1498Szrj while (node != this)
72838fd1498Szrj {
72938fd1498Szrj cgraph_edge *edge = node->get_edge (old_stmt);
73038fd1498Szrj if (edge)
73138fd1498Szrj {
73238fd1498Szrj edge->set_call_stmt (new_stmt, update_speculative);
73338fd1498Szrj /* If UPDATE_SPECULATIVE is false, it means that we are turning
73438fd1498Szrj speculative call into a real code sequence. Update the
73538fd1498Szrj callgraph edges. */
73638fd1498Szrj if (edge->speculative && !update_speculative)
73738fd1498Szrj {
73838fd1498Szrj cgraph_edge *direct, *indirect;
73938fd1498Szrj ipa_ref *ref;
74038fd1498Szrj
74138fd1498Szrj gcc_assert (!edge->indirect_unknown_callee);
74238fd1498Szrj edge->speculative_call_info (direct, indirect, ref);
74338fd1498Szrj direct->speculative = false;
74438fd1498Szrj indirect->speculative = false;
74538fd1498Szrj ref->speculative = false;
74638fd1498Szrj }
74738fd1498Szrj }
74838fd1498Szrj if (node->clones)
74938fd1498Szrj node = node->clones;
75038fd1498Szrj else if (node->next_sibling_clone)
75138fd1498Szrj node = node->next_sibling_clone;
75238fd1498Szrj else
75338fd1498Szrj {
75438fd1498Szrj while (node != this && !node->next_sibling_clone)
75538fd1498Szrj node = node->clone_of;
75638fd1498Szrj if (node != this)
75738fd1498Szrj node = node->next_sibling_clone;
75838fd1498Szrj }
75938fd1498Szrj }
76038fd1498Szrj }
76138fd1498Szrj
76238fd1498Szrj /* Like cgraph_create_edge walk the clone tree and update all clones sharing
76338fd1498Szrj same function body. If clones already have edge for OLD_STMT; only
76438fd1498Szrj update the edge same way as cgraph_set_call_stmt_including_clones does.
76538fd1498Szrj
76638fd1498Szrj TODO: COUNT and LOOP_DEPTH should be properly distributed based on relative
76738fd1498Szrj frequencies of the clones. */
76838fd1498Szrj
76938fd1498Szrj void
create_edge_including_clones(cgraph_node * callee,gimple * old_stmt,gcall * stmt,profile_count count,cgraph_inline_failed_t reason)77038fd1498Szrj cgraph_node::create_edge_including_clones (cgraph_node *callee,
77138fd1498Szrj gimple *old_stmt, gcall *stmt,
77238fd1498Szrj profile_count count,
77338fd1498Szrj cgraph_inline_failed_t reason)
77438fd1498Szrj {
77538fd1498Szrj cgraph_node *node;
77638fd1498Szrj cgraph_edge *edge;
77738fd1498Szrj
77838fd1498Szrj if (!get_edge (stmt))
77938fd1498Szrj {
78038fd1498Szrj edge = create_edge (callee, stmt, count);
78138fd1498Szrj edge->inline_failed = reason;
78238fd1498Szrj }
78338fd1498Szrj
78438fd1498Szrj node = clones;
78538fd1498Szrj if (node)
78638fd1498Szrj while (node != this)
78738fd1498Szrj /* Thunk clones do not get updated while copying inline function body. */
78838fd1498Szrj if (!node->thunk.thunk_p)
78938fd1498Szrj {
79038fd1498Szrj cgraph_edge *edge = node->get_edge (old_stmt);
79138fd1498Szrj
79238fd1498Szrj /* It is possible that clones already contain the edge while
79338fd1498Szrj master didn't. Either we promoted indirect call into direct
79438fd1498Szrj call in the clone or we are processing clones of unreachable
79538fd1498Szrj master where edges has been removed. */
79638fd1498Szrj if (edge)
79738fd1498Szrj edge->set_call_stmt (stmt);
79838fd1498Szrj else if (! node->get_edge (stmt))
79938fd1498Szrj {
80038fd1498Szrj edge = node->create_edge (callee, stmt, count);
80138fd1498Szrj edge->inline_failed = reason;
80238fd1498Szrj }
80338fd1498Szrj
80438fd1498Szrj if (node->clones)
80538fd1498Szrj node = node->clones;
80638fd1498Szrj else if (node->next_sibling_clone)
80738fd1498Szrj node = node->next_sibling_clone;
80838fd1498Szrj else
80938fd1498Szrj {
81038fd1498Szrj while (node != this && !node->next_sibling_clone)
81138fd1498Szrj node = node->clone_of;
81238fd1498Szrj if (node != this)
81338fd1498Szrj node = node->next_sibling_clone;
81438fd1498Szrj }
81538fd1498Szrj }
81638fd1498Szrj }
81738fd1498Szrj
81838fd1498Szrj /* Remove the node from cgraph and all inline clones inlined into it.
81938fd1498Szrj Skip however removal of FORBIDDEN_NODE and return true if it needs to be
82038fd1498Szrj removed. This allows to call the function from outer loop walking clone
82138fd1498Szrj tree. */
82238fd1498Szrj
82338fd1498Szrj bool
remove_symbol_and_inline_clones(cgraph_node * forbidden_node)82438fd1498Szrj cgraph_node::remove_symbol_and_inline_clones (cgraph_node *forbidden_node)
82538fd1498Szrj {
82638fd1498Szrj cgraph_edge *e, *next;
82738fd1498Szrj bool found = false;
82838fd1498Szrj
82938fd1498Szrj if (this == forbidden_node)
83038fd1498Szrj {
83138fd1498Szrj callers->remove ();
83238fd1498Szrj return true;
83338fd1498Szrj }
83438fd1498Szrj for (e = callees; e; e = next)
83538fd1498Szrj {
83638fd1498Szrj next = e->next_callee;
83738fd1498Szrj if (!e->inline_failed)
83838fd1498Szrj found |= e->callee->remove_symbol_and_inline_clones (forbidden_node);
83938fd1498Szrj }
84038fd1498Szrj remove ();
84138fd1498Szrj return found;
84238fd1498Szrj }
84338fd1498Szrj
84438fd1498Szrj /* The edges representing the callers of the NEW_VERSION node were
84538fd1498Szrj fixed by cgraph_function_versioning (), now the call_expr in their
84638fd1498Szrj respective tree code should be updated to call the NEW_VERSION. */
84738fd1498Szrj
84838fd1498Szrj static void
update_call_expr(cgraph_node * new_version)84938fd1498Szrj update_call_expr (cgraph_node *new_version)
85038fd1498Szrj {
85138fd1498Szrj cgraph_edge *e;
85238fd1498Szrj
85338fd1498Szrj gcc_assert (new_version);
85438fd1498Szrj
85538fd1498Szrj /* Update the call expr on the edges to call the new version. */
85638fd1498Szrj for (e = new_version->callers; e; e = e->next_caller)
85738fd1498Szrj {
85838fd1498Szrj function *inner_function = DECL_STRUCT_FUNCTION (e->caller->decl);
85938fd1498Szrj gimple_call_set_fndecl (e->call_stmt, new_version->decl);
86038fd1498Szrj maybe_clean_eh_stmt_fn (inner_function, e->call_stmt);
86138fd1498Szrj }
86238fd1498Szrj }
86338fd1498Szrj
86438fd1498Szrj
86538fd1498Szrj /* Create a new cgraph node which is the new version of
86638fd1498Szrj callgraph node. REDIRECT_CALLERS holds the callers
86738fd1498Szrj edges which should be redirected to point to
86838fd1498Szrj NEW_VERSION. ALL the callees edges of the node
86938fd1498Szrj are cloned to the new version node. Return the new
87038fd1498Szrj version node.
87138fd1498Szrj
87238fd1498Szrj If non-NULL BLOCK_TO_COPY determine what basic blocks
87338fd1498Szrj was copied to prevent duplications of calls that are dead
87438fd1498Szrj in the clone. */
87538fd1498Szrj
87638fd1498Szrj cgraph_node *
create_version_clone(tree new_decl,vec<cgraph_edge * > redirect_callers,bitmap bbs_to_copy,const char * suffix)87738fd1498Szrj cgraph_node::create_version_clone (tree new_decl,
87838fd1498Szrj vec<cgraph_edge *> redirect_callers,
87938fd1498Szrj bitmap bbs_to_copy,
88038fd1498Szrj const char *suffix)
88138fd1498Szrj {
88238fd1498Szrj cgraph_node *new_version;
88338fd1498Szrj cgraph_edge *e;
88438fd1498Szrj unsigned i;
88538fd1498Szrj
88638fd1498Szrj new_version = cgraph_node::create (new_decl);
88738fd1498Szrj
88838fd1498Szrj new_version->analyzed = analyzed;
88938fd1498Szrj new_version->definition = definition;
89038fd1498Szrj new_version->local = local;
89138fd1498Szrj new_version->externally_visible = false;
89238fd1498Szrj new_version->no_reorder = no_reorder;
89338fd1498Szrj new_version->local.local = new_version->definition;
89438fd1498Szrj new_version->global = global;
89538fd1498Szrj new_version->rtl = rtl;
89638fd1498Szrj new_version->count = count;
89738fd1498Szrj
89838fd1498Szrj for (e = callees; e; e=e->next_callee)
89938fd1498Szrj if (!bbs_to_copy
90038fd1498Szrj || bitmap_bit_p (bbs_to_copy, gimple_bb (e->call_stmt)->index))
90138fd1498Szrj e->clone (new_version, e->call_stmt,
90238fd1498Szrj e->lto_stmt_uid, count, count,
90338fd1498Szrj true);
90438fd1498Szrj for (e = indirect_calls; e; e=e->next_callee)
90538fd1498Szrj if (!bbs_to_copy
90638fd1498Szrj || bitmap_bit_p (bbs_to_copy, gimple_bb (e->call_stmt)->index))
90738fd1498Szrj e->clone (new_version, e->call_stmt,
90838fd1498Szrj e->lto_stmt_uid, count, count,
90938fd1498Szrj true);
91038fd1498Szrj FOR_EACH_VEC_ELT (redirect_callers, i, e)
91138fd1498Szrj {
91238fd1498Szrj /* Redirect calls to the old version node to point to its new
91338fd1498Szrj version. */
91438fd1498Szrj e->redirect_callee (new_version);
91538fd1498Szrj }
91638fd1498Szrj
91738fd1498Szrj symtab->call_cgraph_duplication_hooks (this, new_version);
91838fd1498Szrj
91938fd1498Szrj dump_callgraph_transformation (this, new_version, suffix);
92038fd1498Szrj
92138fd1498Szrj return new_version;
92238fd1498Szrj }
92338fd1498Szrj
92438fd1498Szrj /* Perform function versioning.
92538fd1498Szrj Function versioning includes copying of the tree and
92638fd1498Szrj a callgraph update (creating a new cgraph node and updating
92738fd1498Szrj its callees and callers).
92838fd1498Szrj
92938fd1498Szrj REDIRECT_CALLERS varray includes the edges to be redirected
93038fd1498Szrj to the new version.
93138fd1498Szrj
93238fd1498Szrj TREE_MAP is a mapping of tree nodes we want to replace with
93338fd1498Szrj new ones (according to results of prior analysis).
93438fd1498Szrj
93538fd1498Szrj If non-NULL ARGS_TO_SKIP determine function parameters to remove
93638fd1498Szrj from new version.
93738fd1498Szrj If SKIP_RETURN is true, the new version will return void.
93838fd1498Szrj If non-NULL BLOCK_TO_COPY determine what basic blocks to copy.
93938fd1498Szrj If non_NULL NEW_ENTRY determine new entry BB of the clone.
94038fd1498Szrj
941*e215fc28Szrj If TARGET_ATTRIBUTES is non-null, when creating a new declaration,
942*e215fc28Szrj add the attributes to DECL_ATTRIBUTES. And call valid_attribute_p
943*e215fc28Szrj that will promote value of the attribute DECL_FUNCTION_SPECIFIC_TARGET
944*e215fc28Szrj of the declaration.
945*e215fc28Szrj
94638fd1498Szrj Return the new version's cgraph node. */
94738fd1498Szrj
94838fd1498Szrj cgraph_node *
create_version_clone_with_body(vec<cgraph_edge * > redirect_callers,vec<ipa_replace_map *,va_gc> * tree_map,bitmap args_to_skip,bool skip_return,bitmap bbs_to_copy,basic_block new_entry_block,const char * suffix,tree target_attributes)94938fd1498Szrj cgraph_node::create_version_clone_with_body
95038fd1498Szrj (vec<cgraph_edge *> redirect_callers,
95138fd1498Szrj vec<ipa_replace_map *, va_gc> *tree_map, bitmap args_to_skip,
95238fd1498Szrj bool skip_return, bitmap bbs_to_copy, basic_block new_entry_block,
953*e215fc28Szrj const char *suffix, tree target_attributes)
95438fd1498Szrj {
95538fd1498Szrj tree old_decl = decl;
95638fd1498Szrj cgraph_node *new_version_node = NULL;
95738fd1498Szrj tree new_decl;
95838fd1498Szrj
95938fd1498Szrj if (!tree_versionable_function_p (old_decl))
96038fd1498Szrj return NULL;
96138fd1498Szrj
96238fd1498Szrj gcc_assert (local.can_change_signature || !args_to_skip);
96338fd1498Szrj
96438fd1498Szrj /* Make a new FUNCTION_DECL tree node for the new version. */
96538fd1498Szrj if (!args_to_skip && !skip_return)
96638fd1498Szrj new_decl = copy_node (old_decl);
96738fd1498Szrj else
96838fd1498Szrj new_decl
96938fd1498Szrj = build_function_decl_skip_args (old_decl, args_to_skip, skip_return);
97038fd1498Szrj
97138fd1498Szrj /* Generate a new name for the new version. */
97238fd1498Szrj DECL_NAME (new_decl) = clone_function_name (old_decl, suffix);
97338fd1498Szrj SET_DECL_ASSEMBLER_NAME (new_decl, DECL_NAME (new_decl));
97438fd1498Szrj SET_DECL_RTL (new_decl, NULL);
97538fd1498Szrj
976*e215fc28Szrj if (target_attributes)
977*e215fc28Szrj {
978*e215fc28Szrj DECL_ATTRIBUTES (new_decl) = target_attributes;
979*e215fc28Szrj
980*e215fc28Szrj location_t saved_loc = input_location;
981*e215fc28Szrj tree v = TREE_VALUE (target_attributes);
982*e215fc28Szrj input_location = DECL_SOURCE_LOCATION (new_decl);
983*e215fc28Szrj bool r = targetm.target_option.valid_attribute_p (new_decl, NULL, v, 0);
984*e215fc28Szrj input_location = saved_loc;
985*e215fc28Szrj if (!r)
986*e215fc28Szrj return NULL;
987*e215fc28Szrj }
988*e215fc28Szrj
98938fd1498Szrj /* When the old decl was a con-/destructor make sure the clone isn't. */
99038fd1498Szrj DECL_STATIC_CONSTRUCTOR (new_decl) = 0;
99138fd1498Szrj DECL_STATIC_DESTRUCTOR (new_decl) = 0;
99238fd1498Szrj
99338fd1498Szrj /* Create the new version's call-graph node.
99438fd1498Szrj and update the edges of the new node. */
99538fd1498Szrj new_version_node = create_version_clone (new_decl, redirect_callers,
99638fd1498Szrj bbs_to_copy, suffix);
99738fd1498Szrj
99838fd1498Szrj if (ipa_transforms_to_apply.exists ())
99938fd1498Szrj new_version_node->ipa_transforms_to_apply
100038fd1498Szrj = ipa_transforms_to_apply.copy ();
100138fd1498Szrj /* Copy the OLD_VERSION_NODE function tree to the new version. */
100238fd1498Szrj tree_function_versioning (old_decl, new_decl, tree_map, false, args_to_skip,
100338fd1498Szrj skip_return, bbs_to_copy, new_entry_block);
100438fd1498Szrj
100538fd1498Szrj /* Update the new version's properties.
100638fd1498Szrj Make The new version visible only within this translation unit. Make sure
100738fd1498Szrj that is not weak also.
100838fd1498Szrj ??? We cannot use COMDAT linkage because there is no
100938fd1498Szrj ABI support for this. */
101038fd1498Szrj new_version_node->make_decl_local ();
101138fd1498Szrj DECL_VIRTUAL_P (new_version_node->decl) = 0;
101238fd1498Szrj new_version_node->externally_visible = 0;
101338fd1498Szrj new_version_node->local.local = 1;
101438fd1498Szrj new_version_node->lowered = true;
101538fd1498Szrj if (!implicit_section)
101638fd1498Szrj new_version_node->set_section (get_section ());
101738fd1498Szrj /* Clones of global symbols or symbols with unique names are unique. */
101838fd1498Szrj if ((TREE_PUBLIC (old_decl)
101938fd1498Szrj && !DECL_EXTERNAL (old_decl)
102038fd1498Szrj && !DECL_WEAK (old_decl)
102138fd1498Szrj && !DECL_COMDAT (old_decl))
102238fd1498Szrj || in_lto_p)
102338fd1498Szrj new_version_node->unique_name = true;
102438fd1498Szrj
102538fd1498Szrj /* Update the call_expr on the edges to call the new version node. */
102638fd1498Szrj update_call_expr (new_version_node);
102738fd1498Szrj
102838fd1498Szrj symtab->call_cgraph_insertion_hooks (new_version_node);
102938fd1498Szrj return new_version_node;
103038fd1498Szrj }
103138fd1498Szrj
103238fd1498Szrj /* Given virtual clone, turn it into actual clone. */
103338fd1498Szrj
103438fd1498Szrj static void
cgraph_materialize_clone(cgraph_node * node)103538fd1498Szrj cgraph_materialize_clone (cgraph_node *node)
103638fd1498Szrj {
103738fd1498Szrj bitmap_obstack_initialize (NULL);
103838fd1498Szrj node->former_clone_of = node->clone_of->decl;
103938fd1498Szrj if (node->clone_of->former_clone_of)
104038fd1498Szrj node->former_clone_of = node->clone_of->former_clone_of;
104138fd1498Szrj /* Copy the OLD_VERSION_NODE function tree to the new version. */
104238fd1498Szrj tree_function_versioning (node->clone_of->decl, node->decl,
104338fd1498Szrj node->clone.tree_map, true,
104438fd1498Szrj node->clone.args_to_skip, false,
104538fd1498Szrj NULL, NULL);
104638fd1498Szrj if (symtab->dump_file)
104738fd1498Szrj {
104838fd1498Szrj dump_function_to_file (node->clone_of->decl, symtab->dump_file,
104938fd1498Szrj dump_flags);
105038fd1498Szrj dump_function_to_file (node->decl, symtab->dump_file, dump_flags);
105138fd1498Szrj }
105238fd1498Szrj
105338fd1498Szrj /* Function is no longer clone. */
105438fd1498Szrj if (node->next_sibling_clone)
105538fd1498Szrj node->next_sibling_clone->prev_sibling_clone = node->prev_sibling_clone;
105638fd1498Szrj if (node->prev_sibling_clone)
105738fd1498Szrj node->prev_sibling_clone->next_sibling_clone = node->next_sibling_clone;
105838fd1498Szrj else
105938fd1498Szrj node->clone_of->clones = node->next_sibling_clone;
106038fd1498Szrj node->next_sibling_clone = NULL;
106138fd1498Szrj node->prev_sibling_clone = NULL;
106238fd1498Szrj if (!node->clone_of->analyzed && !node->clone_of->clones)
106338fd1498Szrj {
106438fd1498Szrj node->clone_of->release_body ();
106538fd1498Szrj node->clone_of->remove_callees ();
106638fd1498Szrj node->clone_of->remove_all_references ();
106738fd1498Szrj }
106838fd1498Szrj node->clone_of = NULL;
106938fd1498Szrj bitmap_obstack_release (NULL);
107038fd1498Szrj }
107138fd1498Szrj
107238fd1498Szrj /* Once all functions from compilation unit are in memory, produce all clones
107338fd1498Szrj and update all calls. We might also do this on demand if we don't want to
107438fd1498Szrj bring all functions to memory prior compilation, but current WHOPR
107538fd1498Szrj implementation does that and it is a bit easier to keep everything right in
107638fd1498Szrj this order. */
107738fd1498Szrj
107838fd1498Szrj void
materialize_all_clones(void)107938fd1498Szrj symbol_table::materialize_all_clones (void)
108038fd1498Szrj {
108138fd1498Szrj cgraph_node *node;
108238fd1498Szrj bool stabilized = false;
108338fd1498Szrj
108438fd1498Szrj
108538fd1498Szrj if (symtab->dump_file)
108638fd1498Szrj fprintf (symtab->dump_file, "Materializing clones\n");
108738fd1498Szrj
108838fd1498Szrj cgraph_node::checking_verify_cgraph_nodes ();
108938fd1498Szrj
109038fd1498Szrj /* We can also do topological order, but number of iterations should be
109138fd1498Szrj bounded by number of IPA passes since single IPA pass is probably not
109238fd1498Szrj going to create clones of clones it created itself. */
109338fd1498Szrj while (!stabilized)
109438fd1498Szrj {
109538fd1498Szrj stabilized = true;
109638fd1498Szrj FOR_EACH_FUNCTION (node)
109738fd1498Szrj {
109838fd1498Szrj if (node->clone_of && node->decl != node->clone_of->decl
109938fd1498Szrj && !gimple_has_body_p (node->decl))
110038fd1498Szrj {
110138fd1498Szrj if (!node->clone_of->clone_of)
110238fd1498Szrj node->clone_of->get_untransformed_body ();
110338fd1498Szrj if (gimple_has_body_p (node->clone_of->decl))
110438fd1498Szrj {
110538fd1498Szrj if (symtab->dump_file)
110638fd1498Szrj {
110738fd1498Szrj fprintf (symtab->dump_file, "cloning %s to %s\n",
110838fd1498Szrj xstrdup_for_dump (node->clone_of->name ()),
110938fd1498Szrj xstrdup_for_dump (node->name ()));
111038fd1498Szrj if (node->clone.tree_map)
111138fd1498Szrj {
111238fd1498Szrj unsigned int i;
111338fd1498Szrj fprintf (symtab->dump_file, " replace map: ");
111438fd1498Szrj for (i = 0;
111538fd1498Szrj i < vec_safe_length (node->clone.tree_map);
111638fd1498Szrj i++)
111738fd1498Szrj {
111838fd1498Szrj ipa_replace_map *replace_info;
111938fd1498Szrj replace_info = (*node->clone.tree_map)[i];
112038fd1498Szrj print_generic_expr (symtab->dump_file,
112138fd1498Szrj replace_info->old_tree);
112238fd1498Szrj fprintf (symtab->dump_file, " -> ");
112338fd1498Szrj print_generic_expr (symtab->dump_file,
112438fd1498Szrj replace_info->new_tree);
112538fd1498Szrj fprintf (symtab->dump_file, "%s%s;",
112638fd1498Szrj replace_info->replace_p ? "(replace)":"",
112738fd1498Szrj replace_info->ref_p ? "(ref)":"");
112838fd1498Szrj }
112938fd1498Szrj fprintf (symtab->dump_file, "\n");
113038fd1498Szrj }
113138fd1498Szrj if (node->clone.args_to_skip)
113238fd1498Szrj {
113338fd1498Szrj fprintf (symtab->dump_file, " args_to_skip: ");
113438fd1498Szrj dump_bitmap (symtab->dump_file,
113538fd1498Szrj node->clone.args_to_skip);
113638fd1498Szrj }
113738fd1498Szrj if (node->clone.args_to_skip)
113838fd1498Szrj {
113938fd1498Szrj fprintf (symtab->dump_file, " combined_args_to_skip:");
114038fd1498Szrj dump_bitmap (symtab->dump_file, node->clone.combined_args_to_skip);
114138fd1498Szrj }
114238fd1498Szrj }
114338fd1498Szrj cgraph_materialize_clone (node);
114438fd1498Szrj stabilized = false;
114538fd1498Szrj }
114638fd1498Szrj }
114738fd1498Szrj }
114838fd1498Szrj }
114938fd1498Szrj FOR_EACH_FUNCTION (node)
115038fd1498Szrj if (!node->analyzed && node->callees)
115138fd1498Szrj {
115238fd1498Szrj node->remove_callees ();
115338fd1498Szrj node->remove_all_references ();
115438fd1498Szrj }
115538fd1498Szrj else
115638fd1498Szrj node->clear_stmts_in_references ();
115738fd1498Szrj if (symtab->dump_file)
115838fd1498Szrj fprintf (symtab->dump_file, "Materialization Call site updates done.\n");
115938fd1498Szrj
116038fd1498Szrj cgraph_node::checking_verify_cgraph_nodes ();
116138fd1498Szrj
116238fd1498Szrj symtab->remove_unreachable_nodes (symtab->dump_file);
116338fd1498Szrj }
116438fd1498Szrj
116538fd1498Szrj #include "gt-cgraphclones.h"
1166