[Ada] Avoid copy operation for returns involving function calls

gcc/ada/

	* gcc-interface/decl.cc (gnat_to_gnu_entity) <E_Constant>: Deal with
	a constant related to a return in a function specially.
	* gcc-interface/trans.cc (Call_to_gnu): Use return slot optimization
	if the target is a return object.
	(gnat_to_gnu) <N_Object_Declaration>: Deal with a constant related
	to a return in a function specially.
This commit is contained in:
Eric Botcazou 2022-04-12 23:34:48 +02:00 committed by Pierre-Marie de Rodat
parent e4c84b82c5
commit 9aa9ba95ea
2 changed files with 53 additions and 0 deletions

View File

@ -630,6 +630,17 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
break;
case E_Constant:
/* If this is a constant related to a return in a function returning by
invisible reference without expression, get the return object. */
if (Is_Related_To_Func_Return (gnat_entity)
&& current_function_decl
&& TREE_ADDRESSABLE (TREE_TYPE (current_function_decl))
&& !gnu_expr)
{
gnu_decl = DECL_RESULT (current_function_decl);
break;
}
/* Ignore constant definitions already marked with the error node. See
the N_Object_Declaration case of gnat_to_gnu for the rationale. */
if (definition

View File

@ -5281,6 +5281,15 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target,
&& return_slot_opt_for_pure_call_p (gnu_target, gnu_call))
op_code = INIT_EXPR;
/* If this is the initialization of a return object in a function
returning by invisible reference, we can always use the return
slot optimization. */
else if (TREE_CODE (gnu_target) == INDIRECT_REF
&& TREE_CODE (TREE_OPERAND (gnu_target, 0)) == RESULT_DECL
&& current_function_decl
&& TREE_ADDRESSABLE (TREE_TYPE (current_function_decl)))
op_code = INIT_EXPR;
else
op_code = MODIFY_EXPR;
@ -6380,6 +6389,39 @@ gnat_to_gnu (Node_Id gnat_node)
|| Is_Concurrent_Type (Etype (gnat_temp))))
break;
/* If this is a constant related to a return initialized by a reference
to a function call in a function returning by invisible reference:
type Ann is access all Result_Type;
Rnn : constant Ann := Func'reference;
[...]
return Rnn.all;
then elide the temporary by forwarding the return object to Func:
*<retval> = Func (); [return slot optimization]
[...]
return <retval>;
That's necessary if the result type needs finalization because the
temporary would never be adjusted as Expand_Simple_Function_Return
also elides the temporary in this case. */
if (Ekind (gnat_temp) == E_Constant
&& Is_Related_To_Func_Return (gnat_temp)
&& Nkind (Expression (gnat_node)) == N_Reference
&& Nkind (Prefix (Expression (gnat_node))) == N_Function_Call
&& current_function_decl
&& TREE_ADDRESSABLE (TREE_TYPE (current_function_decl)))
{
gnu_result = gnat_to_gnu_entity (gnat_temp, NULL_TREE, true);
gnu_result = build_unary_op (INDIRECT_REF, NULL_TREE, gnu_result);
gnu_result
= Call_to_gnu (Prefix (Expression (gnat_node)),
&gnu_result_type, gnu_result,
NOT_ATOMIC, false);
break;
}
if (Present (Expression (gnat_node))
&& !(kind == N_Object_Declaration && No_Initialization (gnat_node))
&& (!type_annotate_only