aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/gcc/cgraphclones.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.9/gcc/cgraphclones.c')
-rw-r--r--gcc-4.9/gcc/cgraphclones.c339
1 files changed, 216 insertions, 123 deletions
diff --git a/gcc-4.9/gcc/cgraphclones.c b/gcc-4.9/gcc/cgraphclones.c
index ca69033dd..257939cb0 100644
--- a/gcc-4.9/gcc/cgraphclones.c
+++ b/gcc-4.9/gcc/cgraphclones.c
@@ -168,6 +168,212 @@ cgraph_clone_edge (struct cgraph_edge *e, struct cgraph_node *n,
return new_edge;
}
+/* Build variant of function type ORIG_TYPE skipping ARGS_TO_SKIP and the
+ return value if SKIP_RETURN is true. */
+
+static tree
+build_function_type_skip_args (tree orig_type, bitmap args_to_skip,
+ bool skip_return)
+{
+ tree new_type = NULL;
+ tree args, new_args = NULL, t;
+ tree new_reversed;
+ int i = 0;
+
+ for (args = TYPE_ARG_TYPES (orig_type); args && args != void_list_node;
+ args = TREE_CHAIN (args), i++)
+ if (!args_to_skip || !bitmap_bit_p (args_to_skip, i))
+ new_args = tree_cons (NULL_TREE, TREE_VALUE (args), new_args);
+
+ new_reversed = nreverse (new_args);
+ if (args)
+ {
+ if (new_reversed)
+ TREE_CHAIN (new_args) = void_list_node;
+ else
+ new_reversed = void_list_node;
+ }
+
+ /* Use copy_node to preserve as much as possible from original type
+ (debug info, attribute lists etc.)
+ Exception is METHOD_TYPEs must have THIS argument.
+ When we are asked to remove it, we need to build new FUNCTION_TYPE
+ instead. */
+ if (TREE_CODE (orig_type) != METHOD_TYPE
+ || !args_to_skip
+ || !bitmap_bit_p (args_to_skip, 0))
+ {
+ new_type = build_distinct_type_copy (orig_type);
+ TYPE_ARG_TYPES (new_type) = new_reversed;
+ }
+ else
+ {
+ new_type
+ = build_distinct_type_copy (build_function_type (TREE_TYPE (orig_type),
+ new_reversed));
+ TYPE_CONTEXT (new_type) = TYPE_CONTEXT (orig_type);
+ }
+
+ if (skip_return)
+ TREE_TYPE (new_type) = void_type_node;
+
+ /* This is a new type, not a copy of an old type. Need to reassociate
+ variants. We can handle everything except the main variant lazily. */
+ t = TYPE_MAIN_VARIANT (orig_type);
+ if (t != orig_type)
+ {
+ t = build_function_type_skip_args (t, args_to_skip, skip_return);
+ TYPE_MAIN_VARIANT (new_type) = t;
+ TYPE_NEXT_VARIANT (new_type) = TYPE_NEXT_VARIANT (t);
+ TYPE_NEXT_VARIANT (t) = new_type;
+ }
+ else
+ {
+ TYPE_MAIN_VARIANT (new_type) = new_type;
+ TYPE_NEXT_VARIANT (new_type) = NULL;
+ }
+
+ return new_type;
+}
+
+/* Build variant of function decl ORIG_DECL skipping ARGS_TO_SKIP and the
+ return value if SKIP_RETURN is true.
+
+ Arguments from DECL_ARGUMENTS list can't be removed now, since they are
+ linked by TREE_CHAIN directly. The caller is responsible for eliminating
+ them when they are being duplicated (i.e. copy_arguments_for_versioning). */
+
+static tree
+build_function_decl_skip_args (tree orig_decl, bitmap args_to_skip,
+ bool skip_return)
+{
+ tree new_decl = copy_node (orig_decl);
+ tree new_type;
+
+ new_type = TREE_TYPE (orig_decl);
+ if (prototype_p (new_type)
+ || (skip_return && !VOID_TYPE_P (TREE_TYPE (new_type))))
+ new_type
+ = build_function_type_skip_args (new_type, args_to_skip, skip_return);
+ TREE_TYPE (new_decl) = new_type;
+
+ /* For declarations setting DECL_VINDEX (i.e. methods)
+ we expect first argument to be THIS pointer. */
+ if (args_to_skip && bitmap_bit_p (args_to_skip, 0))
+ DECL_VINDEX (new_decl) = NULL_TREE;
+
+ /* When signature changes, we need to clear builtin info. */
+ if (DECL_BUILT_IN (new_decl)
+ && args_to_skip
+ && !bitmap_empty_p (args_to_skip))
+ {
+ DECL_BUILT_IN_CLASS (new_decl) = NOT_BUILT_IN;
+ DECL_FUNCTION_CODE (new_decl) = (enum built_in_function) 0;
+ }
+ /* The FE might have information and assumptions about the other
+ arguments. */
+ DECL_LANG_SPECIFIC (new_decl) = NULL;
+ return new_decl;
+}
+
+/* Set flags of NEW_NODE and its decl. NEW_NODE is a newly created private
+ clone or its thunk. */
+
+static void
+set_new_clone_decl_and_node_flags (cgraph_node *new_node)
+{
+ DECL_EXTERNAL (new_node->decl) = 0;
+ DECL_COMDAT_GROUP (new_node->decl) = 0;
+ TREE_PUBLIC (new_node->decl) = 0;
+ DECL_COMDAT (new_node->decl) = 0;
+ DECL_WEAK (new_node->decl) = 0;
+ DECL_VIRTUAL_P (new_node->decl) = 0;
+ DECL_STATIC_CONSTRUCTOR (new_node->decl) = 0;
+ DECL_STATIC_DESTRUCTOR (new_node->decl) = 0;
+
+ new_node->externally_visible = 0;
+ new_node->local.local = 1;
+ new_node->lowered = true;
+}
+
+/* Duplicate thunk THUNK if necessary but make it to refer to NODE.
+ ARGS_TO_SKIP, if non-NULL, determines which parameters should be omitted.
+ Function can return NODE if no thunk is necessary, which can happen when
+ thunk is this_adjusting but we are removing this parameter. */
+
+static cgraph_node *
+duplicate_thunk_for_node (cgraph_node *thunk, cgraph_node *node,
+ bitmap args_to_skip)
+{
+ cgraph_node *new_thunk, *thunk_of;
+ thunk_of = cgraph_function_or_thunk_node (thunk->callees->callee);
+
+ if (thunk_of->thunk.thunk_p)
+ node = duplicate_thunk_for_node (thunk_of, node, args_to_skip);
+
+ struct cgraph_edge *cs;
+ for (cs = node->callers; cs; cs = cs->next_caller)
+ if (cs->caller->thunk.thunk_p
+ && cs->caller->thunk.this_adjusting == thunk->thunk.this_adjusting
+ && cs->caller->thunk.fixed_offset == thunk->thunk.fixed_offset
+ && cs->caller->thunk.virtual_offset_p == thunk->thunk.virtual_offset_p
+ && cs->caller->thunk.virtual_value == thunk->thunk.virtual_value)
+ return cs->caller;
+
+ tree new_decl;
+ if (!args_to_skip)
+ new_decl = copy_node (thunk->decl);
+ else
+ {
+ /* We do not need to duplicate this_adjusting thunks if we have removed
+ this. */
+ if (thunk->thunk.this_adjusting
+ && bitmap_bit_p (args_to_skip, 0))
+ return node;
+
+ new_decl = build_function_decl_skip_args (thunk->decl, args_to_skip,
+ false);
+ }
+ gcc_checking_assert (!DECL_STRUCT_FUNCTION (new_decl));
+ gcc_checking_assert (!DECL_INITIAL (new_decl));
+ gcc_checking_assert (!DECL_RESULT (new_decl));
+ gcc_checking_assert (!DECL_RTL_SET_P (new_decl));
+
+ DECL_NAME (new_decl) = clone_function_name (thunk->decl, "artificial_thunk");
+ SET_DECL_ASSEMBLER_NAME (new_decl, DECL_NAME (new_decl));
+ DECL_SECTION_NAME (new_decl) = NULL;
+
+ new_thunk = cgraph_create_node (new_decl);
+ set_new_clone_decl_and_node_flags (new_thunk);
+ new_thunk->definition = true;
+ new_thunk->thunk = thunk->thunk;
+ new_thunk->unique_name = in_lto_p;
+ new_thunk->former_clone_of = thunk->decl;
+
+ struct cgraph_edge *e = cgraph_create_edge (new_thunk, node, NULL, 0,
+ CGRAPH_FREQ_BASE);
+ e->call_stmt_cannot_inline_p = true;
+ cgraph_call_edge_duplication_hooks (thunk->callees, e);
+ if (!expand_thunk (new_thunk, false))
+ new_thunk->analyzed = true;
+ cgraph_call_node_duplication_hooks (thunk, new_thunk);
+ return new_thunk;
+}
+
+/* If E does not lead to a thunk, simply redirect it to N. Otherwise create
+ one or more equivalent thunks for N and redirect E to the first in the
+ chain. */
+
+void
+redirect_edge_duplicating_thunks (struct cgraph_edge *e, struct cgraph_node *n,
+ bitmap args_to_skip)
+{
+ cgraph_node *orig_to = cgraph_function_or_thunk_node (e->callee);
+ if (orig_to->thunk.thunk_p)
+ n = duplicate_thunk_for_node (orig_to, n, args_to_skip);
+
+ cgraph_redirect_edge_callee (e, n);
+}
/* Create node representing clone of N executed COUNT times. Decrease
the execution counts from original node too.
@@ -190,7 +396,8 @@ cgraph_clone_node (struct cgraph_node *n, tree decl, gcov_type count, int freq,
bool update_original,
vec<cgraph_edge_p> redirect_callers,
bool call_duplication_hook,
- struct cgraph_node *new_inlined_to)
+ struct cgraph_node *new_inlined_to,
+ bitmap args_to_skip)
{
struct cgraph_node *new_node = cgraph_create_empty_node ();
struct cgraph_edge *e;
@@ -238,8 +445,12 @@ cgraph_clone_node (struct cgraph_node *n, tree decl, gcov_type count, int freq,
FOR_EACH_VEC_ELT (redirect_callers, i, e)
{
/* Redirect calls to the old version node to point to its new
- version. */
- cgraph_redirect_edge_callee (e, new_node);
+ version. The only exception is when the edge was proved to
+ be unreachable during the clonning procedure. */
+ if (!e->callee
+ || DECL_BUILT_IN_CLASS (e->callee->decl) != BUILT_IN_NORMAL
+ || DECL_FUNCTION_CODE (e->callee->decl) != BUILT_IN_UNREACHABLE)
+ redirect_edge_duplicating_thunks (e, new_node, args_to_skip);
}
@@ -288,114 +499,6 @@ clone_function_name (tree decl, const char *suffix)
return get_identifier (tmp_name);
}
-/* Build variant of function type ORIG_TYPE skipping ARGS_TO_SKIP and the
- return value if SKIP_RETURN is true. */
-
-static tree
-build_function_type_skip_args (tree orig_type, bitmap args_to_skip,
- bool skip_return)
-{
- tree new_type = NULL;
- tree args, new_args = NULL, t;
- tree new_reversed;
- int i = 0;
-
- for (args = TYPE_ARG_TYPES (orig_type); args && args != void_list_node;
- args = TREE_CHAIN (args), i++)
- if (!args_to_skip || !bitmap_bit_p (args_to_skip, i))
- new_args = tree_cons (NULL_TREE, TREE_VALUE (args), new_args);
-
- new_reversed = nreverse (new_args);
- if (args)
- {
- if (new_reversed)
- TREE_CHAIN (new_args) = void_list_node;
- else
- new_reversed = void_list_node;
- }
-
- /* Use copy_node to preserve as much as possible from original type
- (debug info, attribute lists etc.)
- Exception is METHOD_TYPEs must have THIS argument.
- When we are asked to remove it, we need to build new FUNCTION_TYPE
- instead. */
- if (TREE_CODE (orig_type) != METHOD_TYPE
- || !args_to_skip
- || !bitmap_bit_p (args_to_skip, 0))
- {
- new_type = build_distinct_type_copy (orig_type);
- TYPE_ARG_TYPES (new_type) = new_reversed;
- }
- else
- {
- new_type
- = build_distinct_type_copy (build_function_type (TREE_TYPE (orig_type),
- new_reversed));
- TYPE_CONTEXT (new_type) = TYPE_CONTEXT (orig_type);
- }
-
- if (skip_return)
- TREE_TYPE (new_type) = void_type_node;
-
- /* This is a new type, not a copy of an old type. Need to reassociate
- variants. We can handle everything except the main variant lazily. */
- t = TYPE_MAIN_VARIANT (orig_type);
- if (t != orig_type)
- {
- t = build_function_type_skip_args (t, args_to_skip, skip_return);
- TYPE_MAIN_VARIANT (new_type) = t;
- TYPE_NEXT_VARIANT (new_type) = TYPE_NEXT_VARIANT (t);
- TYPE_NEXT_VARIANT (t) = new_type;
- }
- else
- {
- TYPE_MAIN_VARIANT (new_type) = new_type;
- TYPE_NEXT_VARIANT (new_type) = NULL;
- }
-
- return new_type;
-}
-
-/* Build variant of function decl ORIG_DECL skipping ARGS_TO_SKIP and the
- return value if SKIP_RETURN is true.
-
- Arguments from DECL_ARGUMENTS list can't be removed now, since they are
- linked by TREE_CHAIN directly. The caller is responsible for eliminating
- them when they are being duplicated (i.e. copy_arguments_for_versioning). */
-
-static tree
-build_function_decl_skip_args (tree orig_decl, bitmap args_to_skip,
- bool skip_return)
-{
- tree new_decl = copy_node (orig_decl);
- tree new_type;
-
- new_type = TREE_TYPE (orig_decl);
- if (prototype_p (new_type)
- || (skip_return && !VOID_TYPE_P (TREE_TYPE (new_type))))
- new_type
- = build_function_type_skip_args (new_type, args_to_skip, skip_return);
- TREE_TYPE (new_decl) = new_type;
-
- /* For declarations setting DECL_VINDEX (i.e. methods)
- we expect first argument to be THIS pointer. */
- if (args_to_skip && bitmap_bit_p (args_to_skip, 0))
- DECL_VINDEX (new_decl) = NULL_TREE;
-
- /* When signature changes, we need to clear builtin info. */
- if (DECL_BUILT_IN (new_decl)
- && args_to_skip
- && !bitmap_empty_p (args_to_skip))
- {
- DECL_BUILT_IN_CLASS (new_decl) = NOT_BUILT_IN;
- DECL_FUNCTION_CODE (new_decl) = (enum built_in_function) 0;
- }
- /* The FE might have information and assumptions about the other
- arguments. */
- DECL_LANG_SPECIFIC (new_decl) = NULL;
- return new_decl;
-}
-
/* Create callgraph node clone with new declaration. The actual body will
be copied later at compilation stage.
@@ -449,22 +552,15 @@ cgraph_create_virtual_clone (struct cgraph_node *old_node,
new_node = cgraph_clone_node (old_node, new_decl, old_node->count,
CGRAPH_FREQ_BASE, false,
- redirect_callers, false, NULL);
+ redirect_callers, false, NULL, args_to_skip);
/* Update the properties.
Make clone visible only within this translation unit. Make sure
that is not weak also.
??? We cannot use COMDAT linkage because there is no
ABI support for this. */
- DECL_EXTERNAL (new_node->decl) = 0;
if (DECL_ONE_ONLY (old_decl))
DECL_SECTION_NAME (new_node->decl) = NULL;
- DECL_COMDAT_GROUP (new_node->decl) = 0;
- TREE_PUBLIC (new_node->decl) = 0;
- DECL_COMDAT (new_node->decl) = 0;
- DECL_WEAK (new_node->decl) = 0;
- DECL_VIRTUAL_P (new_node->decl) = 0;
- DECL_STATIC_CONSTRUCTOR (new_node->decl) = 0;
- DECL_STATIC_DESTRUCTOR (new_node->decl) = 0;
+ set_new_clone_decl_and_node_flags (new_node);
new_node->clone.tree_map = tree_map;
new_node->clone.args_to_skip = args_to_skip;
@@ -504,9 +600,6 @@ cgraph_create_virtual_clone (struct cgraph_node *old_node,
}
else
new_node->clone.combined_args_to_skip = args_to_skip;
- new_node->externally_visible = 0;
- new_node->local.local = 1;
- new_node->lowered = true;
cgraph_call_node_duplication_hooks (old_node, new_node);