summaryrefslogtreecommitdiff
path: root/gcc/cgraphunit.c
diff options
context:
space:
mode:
authorEric Botcazou <ebotcazou@adacore.com>2018-09-28 21:20:53 +0000
committerEric Botcazou <ebotcazou@gcc.gnu.org>2018-09-28 21:20:53 +0000
commit44662f681e8be6b3b7eafcec4afa0ecb8cc587cd (patch)
tree1c0470d4d2c3d3ea333d09879f17a86087934d93 /gcc/cgraphunit.c
parent5c441345a343d0ef90e5ac9ef95039030ecef1ee (diff)
calls.c (expand_call): Try to do a tail call for thunks at -O0 too.
* calls.c (expand_call): Try to do a tail call for thunks at -O0 too. * cgraph.h (struct cgraph_thunk_info): Add indirect_offset. (cgraph_node::create_thunk): Add indirect_offset parameter. (thunk_adjust): Likewise. * cgraph.c (cgraph_node::create_thunk): Add indirect_offset parameter and initialize the corresponding field with it. (cgraph_node::dump): Dump indirect_offset field. * cgraphclones.c (duplicate_thunk_for_node): Deal with indirect_offset. * cgraphunit.c (cgraph_node::analyze): Be prepared for external thunks. (thunk_adjust): Add indirect_offset parameter and deal with it. (cgraph_node::expand_thunk): Deal with the indirect_offset field and pass it to thunk_adjust. Do not call the target hook if it's non-zero or if the thunk is external or local. Fix formatting. Do not chain the RESULT_DECL to BLOCK_VARS. Pass the static chain to the target, if any, in the GIMPLE representation. * ipa-icf.c (sem_function::equals_wpa): Deal with indirect_offset. * lto-cgraph.c (lto_output_node): Write indirect_offset field. (input_node): Read indirect_offset field. * tree-inline.c (expand_call_inline): Pass indirect_offset field in the call to thunk_adjust. * tree-nested.c (struct nesting_info): Add thunk_p field. (create_nesting_tree): Set it. (convert_all_function_calls): Copy static chain from targets to thunks. (finalize_nesting_tree_1): Return early for thunks. (unnest_nesting_tree_1): Do not finalize thunks. (gimplify_all_functions): Do not gimplify thunks. cp/ * method.c (use_thunk): Adjust call to cgraph_node::create_thunk. ada/ * gcc-interface/decl.c (is_cplusplus_method): Do not require C++ convention on Interfaces. * gcc-interface/trans.c (Subprogram_Body_to_gnu): Try to create a bona-fide thunk and hand it over to the middle-end. (get_controlling_type): New function. (use_alias_for_thunk_p): Likewise. (thunk_labelno): New static variable. (make_covariant_thunk): New function. (maybe_make_gnu_thunk): Likewise. * gcc-interface/utils.c (finish_subprog_decl): Set DECL_CONTEXT of the result DECL here instead of... (end_subprog_body): ...here. Co-Authored-By: Pierre-Marie de Rodat <derodat@adacore.com> From-SVN: r264701
Diffstat (limited to 'gcc/cgraphunit.c')
-rw-r--r--gcc/cgraphunit.c118
1 files changed, 90 insertions, 28 deletions
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index ec490d75bd1..c0baaeaefa4 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -623,20 +623,18 @@ cgraph_node::analyze (void)
callees->can_throw_external = !TREE_NOTHROW (t->decl);
/* Target code in expand_thunk may need the thunk's target
to be analyzed, so recurse here. */
- if (!t->analyzed)
+ if (!t->analyzed && t->definition)
t->analyze ();
if (t->alias)
{
t = t->get_alias_target ();
- if (!t->analyzed)
+ if (!t->analyzed && t->definition)
t->analyze ();
}
- if (!expand_thunk (false, false))
- {
- thunk.alias = NULL;
- return;
- }
+ bool ret = expand_thunk (false, false);
thunk.alias = NULL;
+ if (!ret)
+ return;
}
if (alias)
resolve_alias (cgraph_node::get (alias_target), transparent_alias);
@@ -1609,15 +1607,16 @@ init_lowered_empty_function (tree decl, bool in_ssa, profile_count count)
return bb;
}
-/* Adjust PTR by the constant FIXED_OFFSET, and by the vtable
- offset indicated by VIRTUAL_OFFSET, if that is
- non-null. THIS_ADJUSTING is nonzero for a this adjusting thunk and
- zero for a result adjusting thunk. */
+/* Adjust PTR by the constant FIXED_OFFSET, by the vtable offset indicated by
+ VIRTUAL_OFFSET, and by the indirect offset indicated by INDIRECT_OFFSET, if
+ it is non-null. THIS_ADJUSTING is nonzero for a this adjusting thunk and zero
+ for a result adjusting thunk. */
tree
thunk_adjust (gimple_stmt_iterator * bsi,
tree ptr, bool this_adjusting,
- HOST_WIDE_INT fixed_offset, tree virtual_offset)
+ HOST_WIDE_INT fixed_offset, tree virtual_offset,
+ HOST_WIDE_INT indirect_offset)
{
gassign *stmt;
tree ret;
@@ -1632,6 +1631,16 @@ thunk_adjust (gimple_stmt_iterator * bsi,
gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
}
+ if (!vtable_entry_type && (virtual_offset || indirect_offset != 0))
+ {
+ tree vfunc_type = make_node (FUNCTION_TYPE);
+ TREE_TYPE (vfunc_type) = integer_type_node;
+ TYPE_ARG_TYPES (vfunc_type) = NULL_TREE;
+ layout_type (vfunc_type);
+
+ vtable_entry_type = build_pointer_type (vfunc_type);
+ }
+
/* If there's a virtual offset, look up that value in the vtable and
adjust the pointer again. */
if (virtual_offset)
@@ -1640,16 +1649,6 @@ thunk_adjust (gimple_stmt_iterator * bsi,
tree vtabletmp2;
tree vtabletmp3;
- if (!vtable_entry_type)
- {
- tree vfunc_type = make_node (FUNCTION_TYPE);
- TREE_TYPE (vfunc_type) = integer_type_node;
- TYPE_ARG_TYPES (vfunc_type) = NULL_TREE;
- layout_type (vfunc_type);
-
- vtable_entry_type = build_pointer_type (vfunc_type);
- }
-
vtabletmp =
create_tmp_reg (build_pointer_type
(build_pointer_type (vtable_entry_type)), "vptr");
@@ -1687,6 +1686,41 @@ thunk_adjust (gimple_stmt_iterator * bsi,
GSI_CONTINUE_LINKING);
}
+ /* Likewise for an offset that is stored in the object that contains the
+ vtable. */
+ if (indirect_offset != 0)
+ {
+ tree offset_ptr, offset_tree;
+
+ /* Get the address of the offset. */
+ offset_ptr
+ = create_tmp_reg (build_pointer_type
+ (build_pointer_type (vtable_entry_type)),
+ "offset_ptr");
+ stmt = gimple_build_assign (offset_ptr,
+ build1 (NOP_EXPR, TREE_TYPE (offset_ptr),
+ ptr));
+ gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
+
+ stmt = gimple_build_assign
+ (offset_ptr,
+ fold_build_pointer_plus_hwi_loc (input_location, offset_ptr,
+ indirect_offset));
+ gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
+
+ /* Get the offset itself. */
+ offset_tree = create_tmp_reg (TREE_TYPE (TREE_TYPE (offset_ptr)),
+ "offset");
+ stmt = gimple_build_assign (offset_tree,
+ build_simple_mem_ref (offset_ptr));
+ gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
+
+ /* Adjust the `this' pointer. */
+ ptr = fold_build_pointer_plus_loc (input_location, ptr, offset_tree);
+ ptr = force_gimple_operand_gsi (bsi, ptr, true, NULL_TREE, false,
+ GSI_CONTINUE_LINKING);
+ }
+
if (!this_adjusting
&& fixed_offset != 0)
/* Adjust the pointer by the constant. */
@@ -1725,6 +1759,7 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
bool this_adjusting = thunk.this_adjusting;
HOST_WIDE_INT fixed_offset = thunk.fixed_offset;
HOST_WIDE_INT virtual_value = thunk.virtual_value;
+ HOST_WIDE_INT indirect_offset = thunk.indirect_offset;
tree virtual_offset = NULL;
tree alias = callees->callee->decl;
tree thunk_fndecl = decl;
@@ -1735,7 +1770,11 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
if (thunk.add_pointer_bounds_args)
return false;
- if (!force_gimple_thunk && this_adjusting
+ if (!force_gimple_thunk
+ && this_adjusting
+ && indirect_offset == 0
+ && !DECL_EXTERNAL (alias)
+ && !DECL_STATIC_CHAIN (alias)
&& targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset,
virtual_value, alias))
{
@@ -1838,8 +1877,8 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
resdecl = build_decl (input_location, RESULT_DECL, 0, restype);
DECL_ARTIFICIAL (resdecl) = 1;
DECL_IGNORED_P (resdecl) = 1;
+ DECL_CONTEXT (resdecl) = thunk_fndecl;
DECL_RESULT (thunk_fndecl) = resdecl;
- DECL_CONTEXT (DECL_RESULT (thunk_fndecl)) = thunk_fndecl;
}
else
resdecl = DECL_RESULT (thunk_fndecl);
@@ -1876,8 +1915,11 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
restmp = resdecl;
if (VAR_P (restmp))
- add_local_decl (cfun, restmp);
- BLOCK_VARS (DECL_INITIAL (current_function_decl)) = restmp;
+ {
+ add_local_decl (cfun, restmp);
+ BLOCK_VARS (DECL_INITIAL (current_function_decl))
+ = restmp;
+ }
}
else
restmp = create_tmp_var (restype, "retval");
@@ -1894,7 +1936,7 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
if (this_adjusting)
{
vargs.quick_push (thunk_adjust (&bsi, a, 1, fixed_offset,
- virtual_offset));
+ virtual_offset, indirect_offset));
arg = DECL_CHAIN (a);
i = 1;
}
@@ -1919,6 +1961,25 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
call = gimple_build_call_vec (build_fold_addr_expr_loc (0, alias), vargs);
callees->call_stmt = call;
gimple_call_set_from_thunk (call, true);
+ if (DECL_STATIC_CHAIN (alias))
+ {
+ tree p = DECL_STRUCT_FUNCTION (alias)->static_chain_decl;
+ tree type = TREE_TYPE (p);
+ tree decl = build_decl (DECL_SOURCE_LOCATION (thunk_fndecl),
+ PARM_DECL, create_tmp_var_name ("CHAIN"),
+ type);
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_IGNORED_P (decl) = 1;
+ TREE_USED (decl) = 1;
+ DECL_CONTEXT (decl) = thunk_fndecl;
+ DECL_ARG_TYPE (decl) = type;
+ TREE_READONLY (decl) = 1;
+
+ struct function *sf = DECL_STRUCT_FUNCTION (thunk_fndecl);
+ sf->static_chain_decl = decl;
+
+ gimple_call_set_chain (call, decl);
+ }
/* Return slot optimization is always possible and in fact requred to
return values with DECL_BY_REFERENCE. */
@@ -1979,7 +2040,8 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
}
restmp = thunk_adjust (&bsi, restmp, /*this_adjusting=*/0,
- fixed_offset, virtual_offset);
+ fixed_offset, virtual_offset,
+ indirect_offset);
if (true_label)
{
gimple *stmt;