Commit 44662f68 by Eric Botcazou Committed by Eric Botcazou

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
parent 5c441345
2018-09-28 Eric Botcazou <ebotcazou@adacore.com>
Pierre-Marie de Rodat <derodat@adacore.com>
* 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.
2018-09-28 David Malcolm <dmalcolm@redhat.com> 2018-09-28 David Malcolm <dmalcolm@redhat.com>
* opt-suggestions.c (option_proposer::build_option_suggestions): * opt-suggestions.c (option_proposer::build_option_suggestions):
......
2018-09-28 Eric Botcazou <ebotcazou@adacore.com>
Pierre-Marie de Rodat <derodat@adacore.com>
* 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.
2018-09-27 Martin Sebor <msebor@redhat.com> 2018-09-27 Martin Sebor <msebor@redhat.com>
* gcc-interface/utils.c (make_packable_type): Introduce a temporary * gcc-interface/utils.c (make_packable_type): Introduce a temporary
......
...@@ -4851,15 +4851,15 @@ is_cplusplus_method (Entity_Id gnat_entity) ...@@ -4851,15 +4851,15 @@ is_cplusplus_method (Entity_Id gnat_entity)
if (Convention (gnat_entity) != Convention_CPP) if (Convention (gnat_entity) != Convention_CPP)
return false; return false;
/* And that the type of the first parameter (indirectly) has it too. */ /* And that the type of the first parameter (indirectly) has it too, but
we make an exception for Interfaces because they need not be imported. */
Entity_Id gnat_first = First_Formal (gnat_entity); Entity_Id gnat_first = First_Formal (gnat_entity);
if (No (gnat_first)) if (No (gnat_first))
return false; return false;
Entity_Id gnat_type = Etype (gnat_first); Entity_Id gnat_type = Etype (gnat_first);
if (Is_Access_Type (gnat_type)) if (Is_Access_Type (gnat_type))
gnat_type = Directly_Designated_Type (gnat_type); gnat_type = Directly_Designated_Type (gnat_type);
if (Convention (gnat_type) != Convention_CPP) if (Convention (gnat_type) != Convention_CPP && !Is_Interface (gnat_type))
return false; return false;
/* This is the main case: a C++ virtual method imported as a primitive /* This is the main case: a C++ virtual method imported as a primitive
......
...@@ -3294,6 +3294,7 @@ finish_subprog_decl (tree decl, tree asm_name, tree type) ...@@ -3294,6 +3294,7 @@ finish_subprog_decl (tree decl, tree asm_name, tree type)
DECL_ARTIFICIAL (result_decl) = 1; DECL_ARTIFICIAL (result_decl) = 1;
DECL_IGNORED_P (result_decl) = 1; DECL_IGNORED_P (result_decl) = 1;
DECL_CONTEXT (result_decl) = decl;
DECL_BY_REFERENCE (result_decl) = TREE_ADDRESSABLE (type); DECL_BY_REFERENCE (result_decl) = TREE_ADDRESSABLE (type);
DECL_RESULT (decl) = result_decl; DECL_RESULT (decl) = result_decl;
...@@ -3369,9 +3370,6 @@ end_subprog_body (tree body) ...@@ -3369,9 +3370,6 @@ end_subprog_body (tree body)
DECL_INITIAL (fndecl) = current_binding_level->block; DECL_INITIAL (fndecl) = current_binding_level->block;
gnat_poplevel (); gnat_poplevel ();
/* Mark the RESULT_DECL as being in this subprogram. */
DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl;
/* The body should be a BIND_EXPR whose BLOCK is the top-level one. */ /* The body should be a BIND_EXPR whose BLOCK is the top-level one. */
if (TREE_CODE (body) == BIND_EXPR) if (TREE_CODE (body) == BIND_EXPR)
{ {
......
...@@ -3610,9 +3610,8 @@ expand_call (tree exp, rtx target, int ignore) ...@@ -3610,9 +3610,8 @@ expand_call (tree exp, rtx target, int ignore)
pushed these optimizations into -O2. Don't try if we're already pushed these optimizations into -O2. Don't try if we're already
expanding a call, as that means we're an argument. Don't try if expanding a call, as that means we're an argument. Don't try if
there's cleanups, as we know there's code to follow the call. */ there's cleanups, as we know there's code to follow the call. */
if (currently_expanding_call++ != 0 if (currently_expanding_call++ != 0
|| !flag_optimize_sibling_calls || (!flag_optimize_sibling_calls && !CALL_FROM_THUNK_P (exp))
|| args_size.var || args_size.var
|| dbg_cnt (tail_call) == false) || dbg_cnt (tail_call) == false)
try_tail_call = 0; try_tail_call = 0;
......
...@@ -617,6 +617,7 @@ cgraph_node * ...@@ -617,6 +617,7 @@ cgraph_node *
cgraph_node::create_thunk (tree alias, tree, bool this_adjusting, cgraph_node::create_thunk (tree alias, tree, bool this_adjusting,
HOST_WIDE_INT fixed_offset, HOST_WIDE_INT fixed_offset,
HOST_WIDE_INT virtual_value, HOST_WIDE_INT virtual_value,
HOST_WIDE_INT indirect_offset,
tree virtual_offset, tree virtual_offset,
tree real_alias) tree real_alias)
{ {
...@@ -635,6 +636,7 @@ cgraph_node::create_thunk (tree alias, tree, bool this_adjusting, ...@@ -635,6 +636,7 @@ cgraph_node::create_thunk (tree alias, tree, bool this_adjusting,
node->thunk.fixed_offset = fixed_offset; node->thunk.fixed_offset = fixed_offset;
node->thunk.virtual_value = virtual_value; node->thunk.virtual_value = virtual_value;
node->thunk.indirect_offset = indirect_offset;
node->thunk.alias = real_alias; node->thunk.alias = real_alias;
node->thunk.this_adjusting = this_adjusting; node->thunk.this_adjusting = this_adjusting;
node->thunk.virtual_offset_p = virtual_offset != NULL; node->thunk.virtual_offset_p = virtual_offset != NULL;
...@@ -2099,10 +2101,11 @@ cgraph_node::dump (FILE *f) ...@@ -2099,10 +2101,11 @@ cgraph_node::dump (FILE *f)
fprintf (f, " of %s (asm: %s)", fprintf (f, " of %s (asm: %s)",
lang_hooks.decl_printable_name (thunk.alias, 2), lang_hooks.decl_printable_name (thunk.alias, 2),
IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (thunk.alias))); IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (thunk.alias)));
fprintf (f, " fixed offset %i virtual value %i has " fprintf (f, " fixed offset %i virtual value %i indirect_offset %i "
"virtual offset %i)\n", "has virtual offset %i\n",
(int)thunk.fixed_offset, (int)thunk.fixed_offset,
(int)thunk.virtual_value, (int)thunk.virtual_value,
(int)thunk.indirect_offset,
(int)thunk.virtual_offset_p); (int)thunk.virtual_offset_p);
} }
if (alias && thunk.alias if (alias && thunk.alias
......
...@@ -666,6 +666,10 @@ struct GTY(()) cgraph_thunk_info { ...@@ -666,6 +666,10 @@ struct GTY(()) cgraph_thunk_info {
VIRTUAL_OFFSET_P is true. */ VIRTUAL_OFFSET_P is true. */
HOST_WIDE_INT virtual_value; HOST_WIDE_INT virtual_value;
/* Offset from "this" to get the offset to adjust "this". Zero means: this
offset is to be ignored. */
HOST_WIDE_INT indirect_offset;
/* Thunk target, i.e. the method that this thunk wraps. Depending on the /* Thunk target, i.e. the method that this thunk wraps. Depending on the
TARGET_USE_LOCAL_THUNK_ALIAS_P macro, this may have to be a new alias. */ TARGET_USE_LOCAL_THUNK_ALIAS_P macro, this may have to be a new alias. */
tree alias; tree alias;
...@@ -1033,6 +1037,7 @@ public: ...@@ -1033,6 +1037,7 @@ public:
cgraph_node * create_thunk (tree alias, tree, bool this_adjusting, cgraph_node * create_thunk (tree alias, tree, bool this_adjusting,
HOST_WIDE_INT fixed_offset, HOST_WIDE_INT fixed_offset,
HOST_WIDE_INT virtual_value, HOST_WIDE_INT virtual_value,
HOST_WIDE_INT indirect_offset,
tree virtual_offset, tree virtual_offset,
tree real_alias); tree real_alias);
...@@ -2373,7 +2378,8 @@ void cgraphunit_c_finalize (void); ...@@ -2373,7 +2378,8 @@ void cgraphunit_c_finalize (void);
IN_SSA is true if the gimple is in SSA. */ IN_SSA is true if the gimple is in SSA. */
basic_block init_lowered_empty_function (tree, bool, profile_count); basic_block init_lowered_empty_function (tree, bool, profile_count);
tree thunk_adjust (gimple_stmt_iterator *, tree, bool, HOST_WIDE_INT, tree); tree thunk_adjust (gimple_stmt_iterator *, tree, bool, HOST_WIDE_INT, tree,
HOST_WIDE_INT);
/* In cgraphclones.c */ /* In cgraphclones.c */
tree clone_function_name_1 (const char *, const char *); tree clone_function_name_1 (const char *, const char *);
......
...@@ -274,10 +274,11 @@ duplicate_thunk_for_node (cgraph_node *thunk, cgraph_node *node) ...@@ -274,10 +274,11 @@ duplicate_thunk_for_node (cgraph_node *thunk, cgraph_node *node)
cgraph_edge *cs; cgraph_edge *cs;
for (cs = node->callers; cs; cs = cs->next_caller) for (cs = node->callers; cs; cs = cs->next_caller)
if (cs->caller->thunk.thunk_p 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.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
&& cs->caller->thunk.virtual_value == thunk->thunk.virtual_value) && cs->caller->thunk.indirect_offset == thunk->thunk.indirect_offset
&& cs->caller->thunk.this_adjusting == thunk->thunk.this_adjusting
&& cs->caller->thunk.virtual_offset_p == thunk->thunk.virtual_offset_p)
return cs->caller; return cs->caller;
tree new_decl; tree new_decl;
......
...@@ -623,20 +623,18 @@ cgraph_node::analyze (void) ...@@ -623,20 +623,18 @@ cgraph_node::analyze (void)
callees->can_throw_external = !TREE_NOTHROW (t->decl); callees->can_throw_external = !TREE_NOTHROW (t->decl);
/* Target code in expand_thunk may need the thunk's target /* Target code in expand_thunk may need the thunk's target
to be analyzed, so recurse here. */ to be analyzed, so recurse here. */
if (!t->analyzed) if (!t->analyzed && t->definition)
t->analyze (); t->analyze ();
if (t->alias) if (t->alias)
{ {
t = t->get_alias_target (); t = t->get_alias_target ();
if (!t->analyzed) if (!t->analyzed && t->definition)
t->analyze (); t->analyze ();
} }
if (!expand_thunk (false, false)) bool ret = expand_thunk (false, false);
{
thunk.alias = NULL;
return;
}
thunk.alias = NULL; thunk.alias = NULL;
if (!ret)
return;
} }
if (alias) if (alias)
resolve_alias (cgraph_node::get (alias_target), transparent_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) ...@@ -1609,15 +1607,16 @@ init_lowered_empty_function (tree decl, bool in_ssa, profile_count count)
return bb; return bb;
} }
/* Adjust PTR by the constant FIXED_OFFSET, and by the vtable /* Adjust PTR by the constant FIXED_OFFSET, by the vtable offset indicated by
offset indicated by VIRTUAL_OFFSET, if that is VIRTUAL_OFFSET, and by the indirect offset indicated by INDIRECT_OFFSET, if
non-null. THIS_ADJUSTING is nonzero for a this adjusting thunk and it is non-null. THIS_ADJUSTING is nonzero for a this adjusting thunk and zero
zero for a result adjusting thunk. */ for a result adjusting thunk. */
tree tree
thunk_adjust (gimple_stmt_iterator * bsi, thunk_adjust (gimple_stmt_iterator * bsi,
tree ptr, bool this_adjusting, 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; gassign *stmt;
tree ret; tree ret;
...@@ -1632,6 +1631,16 @@ thunk_adjust (gimple_stmt_iterator * bsi, ...@@ -1632,6 +1631,16 @@ thunk_adjust (gimple_stmt_iterator * bsi,
gsi_insert_after (bsi, stmt, GSI_NEW_STMT); 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 /* If there's a virtual offset, look up that value in the vtable and
adjust the pointer again. */ adjust the pointer again. */
if (virtual_offset) if (virtual_offset)
...@@ -1640,16 +1649,6 @@ thunk_adjust (gimple_stmt_iterator * bsi, ...@@ -1640,16 +1649,6 @@ thunk_adjust (gimple_stmt_iterator * bsi,
tree vtabletmp2; tree vtabletmp2;
tree vtabletmp3; 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 = vtabletmp =
create_tmp_reg (build_pointer_type create_tmp_reg (build_pointer_type
(build_pointer_type (vtable_entry_type)), "vptr"); (build_pointer_type (vtable_entry_type)), "vptr");
...@@ -1687,6 +1686,41 @@ thunk_adjust (gimple_stmt_iterator * bsi, ...@@ -1687,6 +1686,41 @@ thunk_adjust (gimple_stmt_iterator * bsi,
GSI_CONTINUE_LINKING); 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 if (!this_adjusting
&& fixed_offset != 0) && fixed_offset != 0)
/* Adjust the pointer by the constant. */ /* Adjust the pointer by the constant. */
...@@ -1725,6 +1759,7 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk) ...@@ -1725,6 +1759,7 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
bool this_adjusting = thunk.this_adjusting; bool this_adjusting = thunk.this_adjusting;
HOST_WIDE_INT fixed_offset = thunk.fixed_offset; HOST_WIDE_INT fixed_offset = thunk.fixed_offset;
HOST_WIDE_INT virtual_value = thunk.virtual_value; HOST_WIDE_INT virtual_value = thunk.virtual_value;
HOST_WIDE_INT indirect_offset = thunk.indirect_offset;
tree virtual_offset = NULL; tree virtual_offset = NULL;
tree alias = callees->callee->decl; tree alias = callees->callee->decl;
tree thunk_fndecl = decl; tree thunk_fndecl = decl;
...@@ -1735,7 +1770,11 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk) ...@@ -1735,7 +1770,11 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
if (thunk.add_pointer_bounds_args) if (thunk.add_pointer_bounds_args)
return false; 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, && targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset,
virtual_value, alias)) virtual_value, alias))
{ {
...@@ -1838,8 +1877,8 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk) ...@@ -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); resdecl = build_decl (input_location, RESULT_DECL, 0, restype);
DECL_ARTIFICIAL (resdecl) = 1; DECL_ARTIFICIAL (resdecl) = 1;
DECL_IGNORED_P (resdecl) = 1; DECL_IGNORED_P (resdecl) = 1;
DECL_CONTEXT (resdecl) = thunk_fndecl;
DECL_RESULT (thunk_fndecl) = resdecl; DECL_RESULT (thunk_fndecl) = resdecl;
DECL_CONTEXT (DECL_RESULT (thunk_fndecl)) = thunk_fndecl;
} }
else else
resdecl = DECL_RESULT (thunk_fndecl); resdecl = DECL_RESULT (thunk_fndecl);
...@@ -1876,8 +1915,11 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk) ...@@ -1876,8 +1915,11 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
restmp = resdecl; restmp = resdecl;
if (VAR_P (restmp)) 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 else
restmp = create_tmp_var (restype, "retval"); restmp = create_tmp_var (restype, "retval");
...@@ -1894,7 +1936,7 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk) ...@@ -1894,7 +1936,7 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
if (this_adjusting) if (this_adjusting)
{ {
vargs.quick_push (thunk_adjust (&bsi, a, 1, fixed_offset, vargs.quick_push (thunk_adjust (&bsi, a, 1, fixed_offset,
virtual_offset)); virtual_offset, indirect_offset));
arg = DECL_CHAIN (a); arg = DECL_CHAIN (a);
i = 1; i = 1;
} }
...@@ -1919,6 +1961,25 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk) ...@@ -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); call = gimple_build_call_vec (build_fold_addr_expr_loc (0, alias), vargs);
callees->call_stmt = call; callees->call_stmt = call;
gimple_call_set_from_thunk (call, true); 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 slot optimization is always possible and in fact requred to
return values with DECL_BY_REFERENCE. */ return values with DECL_BY_REFERENCE. */
...@@ -1979,7 +2040,8 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk) ...@@ -1979,7 +2040,8 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
} }
restmp = thunk_adjust (&bsi, restmp, /*this_adjusting=*/0, restmp = thunk_adjust (&bsi, restmp, /*this_adjusting=*/0,
fixed_offset, virtual_offset); fixed_offset, virtual_offset,
indirect_offset);
if (true_label) if (true_label)
{ {
gimple *stmt; gimple *stmt;
......
2018-09-28 Eric Botcazou <ebotcazou@adacore.com>
Pierre-Marie de Rodat <derodat@adacore.com>
* method.c (use_thunk): Adjust call to cgraph_node::create_thunk.
2018-09-28 Richard Biener <rguenther@suse.de> 2018-09-28 Richard Biener <rguenther@suse.de>
* error.c (cp_print_error_function): Simplify by eliding * error.c (cp_print_error_function): Simplify by eliding
......
...@@ -375,7 +375,7 @@ use_thunk (tree thunk_fndecl, bool emit_p) ...@@ -375,7 +375,7 @@ use_thunk (tree thunk_fndecl, bool emit_p)
gcc_checking_assert (funcn); gcc_checking_assert (funcn);
thunk_node = funcn->create_thunk (thunk_fndecl, function, thunk_node = funcn->create_thunk (thunk_fndecl, function,
this_adjusting, fixed_offset, virtual_value, this_adjusting, fixed_offset, virtual_value,
virtual_offset, alias); 0, virtual_offset, alias);
if (DECL_ONE_ONLY (function)) if (DECL_ONE_ONLY (function))
thunk_node->add_to_same_comdat_group (funcn); thunk_node->add_to_same_comdat_group (funcn);
......
...@@ -593,6 +593,8 @@ sem_function::equals_wpa (sem_item *item, ...@@ -593,6 +593,8 @@ sem_function::equals_wpa (sem_item *item,
return return_false_with_msg ("thunk fixed_offset mismatch"); return return_false_with_msg ("thunk fixed_offset mismatch");
if (cnode->thunk.virtual_value != cnode2->thunk.virtual_value) if (cnode->thunk.virtual_value != cnode2->thunk.virtual_value)
return return_false_with_msg ("thunk virtual_value mismatch"); return return_false_with_msg ("thunk virtual_value mismatch");
if (cnode->thunk.indirect_offset != cnode2->thunk.indirect_offset)
return return_false_with_msg ("thunk indirect_offset mismatch");
if (cnode->thunk.this_adjusting != cnode2->thunk.this_adjusting) if (cnode->thunk.this_adjusting != cnode2->thunk.this_adjusting)
return return_false_with_msg ("thunk this_adjusting mismatch"); return return_false_with_msg ("thunk this_adjusting mismatch");
if (cnode->thunk.virtual_offset_p != cnode2->thunk.virtual_offset_p) if (cnode->thunk.virtual_offset_p != cnode2->thunk.virtual_offset_p)
......
...@@ -556,6 +556,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, ...@@ -556,6 +556,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
+ (node->thunk.add_pointer_bounds_args != 0) * 8); + (node->thunk.add_pointer_bounds_args != 0) * 8);
streamer_write_uhwi_stream (ob->main_stream, node->thunk.fixed_offset); streamer_write_uhwi_stream (ob->main_stream, node->thunk.fixed_offset);
streamer_write_uhwi_stream (ob->main_stream, node->thunk.virtual_value); streamer_write_uhwi_stream (ob->main_stream, node->thunk.virtual_value);
streamer_write_uhwi_stream (ob->main_stream, node->thunk.indirect_offset);
} }
streamer_write_hwi_stream (ob->main_stream, node->profile_id); streamer_write_hwi_stream (ob->main_stream, node->profile_id);
if (DECL_STATIC_CONSTRUCTOR (node->decl)) if (DECL_STATIC_CONSTRUCTOR (node->decl))
...@@ -1271,10 +1272,12 @@ input_node (struct lto_file_decl_data *file_data, ...@@ -1271,10 +1272,12 @@ input_node (struct lto_file_decl_data *file_data,
int type = streamer_read_uhwi (ib); int type = streamer_read_uhwi (ib);
HOST_WIDE_INT fixed_offset = streamer_read_uhwi (ib); HOST_WIDE_INT fixed_offset = streamer_read_uhwi (ib);
HOST_WIDE_INT virtual_value = streamer_read_uhwi (ib); HOST_WIDE_INT virtual_value = streamer_read_uhwi (ib);
HOST_WIDE_INT indirect_offset = streamer_read_uhwi (ib);
node->thunk.fixed_offset = fixed_offset; node->thunk.fixed_offset = fixed_offset;
node->thunk.this_adjusting = (type & 2);
node->thunk.virtual_value = virtual_value; node->thunk.virtual_value = virtual_value;
node->thunk.indirect_offset = indirect_offset;
node->thunk.this_adjusting = (type & 2);
node->thunk.virtual_offset_p = (type & 4); node->thunk.virtual_offset_p = (type & 4);
node->thunk.add_pointer_bounds_args = (type & 8); node->thunk.add_pointer_bounds_args = (type & 8);
} }
......
...@@ -4473,7 +4473,7 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id) ...@@ -4473,7 +4473,7 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id)
GSI_NEW_STMT); GSI_NEW_STMT);
gcc_assert (id->src_node->thunk.this_adjusting); gcc_assert (id->src_node->thunk.this_adjusting);
op = thunk_adjust (&iter, op, 1, id->src_node->thunk.fixed_offset, op = thunk_adjust (&iter, op, 1, id->src_node->thunk.fixed_offset,
virtual_offset); virtual_offset, id->src_node->thunk.indirect_offset);
gimple_call_set_arg (stmt, 0, op); gimple_call_set_arg (stmt, 0, op);
gimple_call_set_fndecl (stmt, edge->callee->decl); gimple_call_set_fndecl (stmt, edge->callee->decl);
......
...@@ -104,6 +104,7 @@ struct nesting_info ...@@ -104,6 +104,7 @@ struct nesting_info
tree chain_decl; tree chain_decl;
tree nl_goto_field; tree nl_goto_field;
bool thunk_p;
bool any_parm_remapped; bool any_parm_remapped;
bool any_tramp_created; bool any_tramp_created;
bool any_descr_created; bool any_descr_created;
...@@ -834,6 +835,7 @@ create_nesting_tree (struct cgraph_node *cgn) ...@@ -834,6 +835,7 @@ create_nesting_tree (struct cgraph_node *cgn)
info->mem_refs = new hash_set<tree *>; info->mem_refs = new hash_set<tree *>;
info->suppress_expansion = BITMAP_ALLOC (&nesting_info_bitmap_obstack); info->suppress_expansion = BITMAP_ALLOC (&nesting_info_bitmap_obstack);
info->context = cgn->decl; info->context = cgn->decl;
info->thunk_p = cgn->thunk.thunk_p;
for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested) for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested)
{ {
...@@ -2786,6 +2788,8 @@ convert_all_function_calls (struct nesting_info *root) ...@@ -2786,6 +2788,8 @@ convert_all_function_calls (struct nesting_info *root)
within the debugger. */ within the debugger. */
FOR_EACH_NEST_INFO (n, root) FOR_EACH_NEST_INFO (n, root)
{ {
if (n->thunk_p)
continue;
tree decl = n->context; tree decl = n->context;
if (!optimize) if (!optimize)
{ {
...@@ -2806,6 +2810,14 @@ convert_all_function_calls (struct nesting_info *root) ...@@ -2806,6 +2810,14 @@ convert_all_function_calls (struct nesting_info *root)
chain_count += DECL_STATIC_CHAIN (decl); chain_count += DECL_STATIC_CHAIN (decl);
} }
FOR_EACH_NEST_INFO (n, root)
if (n->thunk_p)
{
tree decl = n->context;
tree alias = cgraph_node::get (decl)->thunk.alias;
DECL_STATIC_CHAIN (decl) = DECL_STATIC_CHAIN (alias);
}
/* Walk the functions and perform transformations. Note that these /* Walk the functions and perform transformations. Note that these
transformations can induce new uses of the static chain, which in turn transformations can induce new uses of the static chain, which in turn
require re-examining all users of the decl. */ require re-examining all users of the decl. */
...@@ -2825,12 +2837,22 @@ convert_all_function_calls (struct nesting_info *root) ...@@ -2825,12 +2837,22 @@ convert_all_function_calls (struct nesting_info *root)
FOR_EACH_NEST_INFO (n, root) FOR_EACH_NEST_INFO (n, root)
{ {
if (n->thunk_p)
continue;
tree decl = n->context; tree decl = n->context;
walk_function (convert_tramp_reference_stmt, walk_function (convert_tramp_reference_stmt,
convert_tramp_reference_op, n); convert_tramp_reference_op, n);
walk_function (convert_gimple_call, NULL, n); walk_function (convert_gimple_call, NULL, n);
chain_count += DECL_STATIC_CHAIN (decl); chain_count += DECL_STATIC_CHAIN (decl);
} }
FOR_EACH_NEST_INFO (n, root)
if (n->thunk_p)
{
tree decl = n->context;
tree alias = cgraph_node::get (decl)->thunk.alias;
DECL_STATIC_CHAIN (decl) = DECL_STATIC_CHAIN (alias);
}
} }
while (chain_count != old_chain_count); while (chain_count != old_chain_count);
...@@ -3055,12 +3077,13 @@ build_init_call_stmt (struct nesting_info *info, tree decl, tree field, ...@@ -3055,12 +3077,13 @@ build_init_call_stmt (struct nesting_info *info, tree decl, tree field,
static void static void
finalize_nesting_tree_1 (struct nesting_info *root) finalize_nesting_tree_1 (struct nesting_info *root)
{ {
gimple_seq stmt_list; gimple_seq stmt_list = NULL;
gimple *stmt; gimple *stmt;
tree context = root->context; tree context = root->context;
struct function *sf; struct function *sf;
stmt_list = NULL; if (root->thunk_p)
return;
/* If we created a non-local frame type or decl, we need to lay them /* If we created a non-local frame type or decl, we need to lay them
out at this time. */ out at this time. */
...@@ -3340,7 +3363,8 @@ unnest_nesting_tree_1 (struct nesting_info *root) ...@@ -3340,7 +3363,8 @@ unnest_nesting_tree_1 (struct nesting_info *root)
if (node->origin) if (node->origin)
{ {
node->unnest (); node->unnest ();
cgraph_node::finalize_function (root->context, true); if (!root->thunk_p)
cgraph_node::finalize_function (root->context, true);
} }
} }
...@@ -3380,7 +3404,8 @@ gimplify_all_functions (struct cgraph_node *root) ...@@ -3380,7 +3404,8 @@ gimplify_all_functions (struct cgraph_node *root)
if (!gimple_body (root->decl)) if (!gimple_body (root->decl))
gimplify_function_tree (root->decl); gimplify_function_tree (root->decl);
for (iter = root->nested; iter; iter = iter->next_nested) for (iter = root->nested; iter; iter = iter->next_nested)
gimplify_all_functions (iter); if (!iter->thunk.thunk_p)
gimplify_all_functions (iter);
} }
/* Main entry point for this pass. Process FNDECL and all of its nested /* Main entry point for this pass. Process FNDECL and all of its nested
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment