Commit 5d2a63dc by Eric Botcazou Committed by Eric Botcazou

trans.c (finalize_nrv_r): Remove obsolete code.

	* gcc-interface/trans.c (finalize_nrv_r): Remove obsolete code.
	(build_return_expr): Likewise.
	(Call_to_gnu): If this is a function call and there is no target,
	create a temporary for the return value for all aggregate types,
	but never create it for a return statement.  Push a binding level
	around the call in more cases.  Remove obsolete code.

From-SVN: r233805
parent 93e708f9
2016-02-29 Eric Botcazou <ebotcazou@adacore.com> 2016-02-29 Eric Botcazou <ebotcazou@adacore.com>
* gcc-interface/trans.c (finalize_nrv_r): Remove obsolete code.
(build_return_expr): Likewise.
(Call_to_gnu): If this is a function call and there is no target,
create a temporary for the return value for all aggregate types,
but never create it for a return statement. Push a binding level
around the call in more cases. Remove obsolete code.
2016-02-29 Eric Botcazou <ebotcazou@adacore.com>
* gcc-interface/ada-tree.h (DECL_RETURN_VALUE_P): New macro. * gcc-interface/ada-tree.h (DECL_RETURN_VALUE_P): New macro.
* gcc-interface/gigi.h (gigi): Remove useless attribute. * gcc-interface/gigi.h (gigi): Remove useless attribute.
(gnat_gimplify_expr): Likewise. (gnat_gimplify_expr): Likewise.
......
...@@ -3330,32 +3330,14 @@ finalize_nrv_r (tree *tp, int *walk_subtrees, void *data) ...@@ -3330,32 +3330,14 @@ finalize_nrv_r (tree *tp, int *walk_subtrees, void *data)
else if (TREE_CODE (t) == RETURN_EXPR else if (TREE_CODE (t) == RETURN_EXPR
&& TREE_CODE (TREE_OPERAND (t, 0)) == INIT_EXPR) && TREE_CODE (TREE_OPERAND (t, 0)) == INIT_EXPR)
{ {
tree ret_val = TREE_OPERAND (TREE_OPERAND (t, 0), 1), init_expr; tree ret_val = TREE_OPERAND (TREE_OPERAND (t, 0), 1);
/* If this is the temporary created for a return value with variable
size in Call_to_gnu, we replace the RHS with the init expression. */
if (TREE_CODE (ret_val) == COMPOUND_EXPR
&& TREE_CODE (TREE_OPERAND (ret_val, 0)) == INIT_EXPR
&& TREE_OPERAND (TREE_OPERAND (ret_val, 0), 0)
== TREE_OPERAND (ret_val, 1))
{
init_expr = TREE_OPERAND (TREE_OPERAND (ret_val, 0), 1);
ret_val = TREE_OPERAND (ret_val, 1);
}
else
init_expr = NULL_TREE;
/* Strip useless conversions around the return value. */ /* Strip useless conversions around the return value. */
if (gnat_useless_type_conversion (ret_val)) if (gnat_useless_type_conversion (ret_val))
ret_val = TREE_OPERAND (ret_val, 0); ret_val = TREE_OPERAND (ret_val, 0);
if (is_nrv_p (dp->nrv, ret_val)) if (is_nrv_p (dp->nrv, ret_val))
{ TREE_OPERAND (t, 0) = dp->result;
if (init_expr)
TREE_OPERAND (TREE_OPERAND (t, 0), 1) = init_expr;
else
TREE_OPERAND (t, 0) = dp->result;
}
} }
/* Replace the DECL_EXPR of NRVs with an initialization of the RESULT_DECL, /* Replace the DECL_EXPR of NRVs with an initialization of the RESULT_DECL,
...@@ -3659,14 +3641,6 @@ build_return_expr (tree ret_obj, tree ret_val) ...@@ -3659,14 +3641,6 @@ build_return_expr (tree ret_obj, tree ret_val)
&& TYPE_MODE (operation_type) == BLKmode && TYPE_MODE (operation_type) == BLKmode
&& aggregate_value_p (operation_type, current_function_decl)) && aggregate_value_p (operation_type, current_function_decl))
{ {
/* Recognize the temporary created for a return value with variable
size in Call_to_gnu. We want to eliminate it if possible. */
if (TREE_CODE (ret_val) == COMPOUND_EXPR
&& TREE_CODE (TREE_OPERAND (ret_val, 0)) == INIT_EXPR
&& TREE_OPERAND (TREE_OPERAND (ret_val, 0), 0)
== TREE_OPERAND (ret_val, 1))
ret_val = TREE_OPERAND (ret_val, 1);
/* Strip useless conversions around the return value. */ /* Strip useless conversions around the return value. */
if (gnat_useless_type_conversion (ret_val)) if (gnat_useless_type_conversion (ret_val))
ret_val = TREE_OPERAND (ret_val, 0); ret_val = TREE_OPERAND (ret_val, 0);
...@@ -4314,14 +4288,22 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, ...@@ -4314,14 +4288,22 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target,
because we need to preserve the return value before copying back the because we need to preserve the return value before copying back the
parameters. parameters.
2. There is no target and this is neither an object nor a renaming 2. There is no target and the call is made for neither an object nor a
declaration, and the return type has variable size, because in renaming declaration, nor a return statement, and the return type has
these cases the gimplifier cannot create the temporary. variable size, because in this case the gimplifier cannot create the
temporary, or more generally is simply an aggregate type, because the
gimplifier would create the temporary in the outermost scope instead
of locally.
3. There is a target and it is a slice or an array with fixed size, 3. There is a target and it is a slice or an array with fixed size,
and the return type has variable size, because the gimplifier and the return type has variable size, because the gimplifier
doesn't handle these cases. doesn't handle these cases.
4. There is no target and we have misaligned In Out or Out parameters
passed by reference, because we need to preserve the return value
before copying back the parameters. However, in this case, we'll
defer creating the temporary, see below.
This must be done before we push a binding level around the call, since This must be done before we push a binding level around the call, since
we will pop it before copying the return value. */ we will pop it before copying the return value. */
if (function_call if (function_call
...@@ -4329,7 +4311,9 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, ...@@ -4329,7 +4311,9 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target,
|| (!gnu_target || (!gnu_target
&& Nkind (Parent (gnat_node)) != N_Object_Declaration && Nkind (Parent (gnat_node)) != N_Object_Declaration
&& Nkind (Parent (gnat_node)) != N_Object_Renaming_Declaration && Nkind (Parent (gnat_node)) != N_Object_Renaming_Declaration
&& TREE_CODE (TYPE_SIZE (gnu_result_type)) != INTEGER_CST) && Nkind (Parent (gnat_node)) != N_Simple_Return_Statement
&& AGGREGATE_TYPE_P (gnu_result_type)
&& !TYPE_IS_FAT_POINTER_P (gnu_result_type))
|| (gnu_target || (gnu_target
&& (TREE_CODE (gnu_target) == ARRAY_RANGE_REF && (TREE_CODE (gnu_target) == ARRAY_RANGE_REF
|| (TREE_CODE (TREE_TYPE (gnu_target)) == ARRAY_TYPE || (TREE_CODE (TREE_TYPE (gnu_target)) == ARRAY_TYPE
...@@ -4341,6 +4325,16 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, ...@@ -4341,6 +4325,16 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target,
DECL_RETURN_VALUE_P (gnu_retval) = 1; DECL_RETURN_VALUE_P (gnu_retval) = 1;
} }
/* If we don't need a value or have already created it, push a binding level
around the call. This will narrow the lifetime of the temporaries we may
need to make when translating the parameters as much as possible. */
if (!returning_value || gnu_retval)
{
start_stmt_group ();
gnat_pushlevel ();
pushed_binding_level = true;
}
/* Create the list of the actual parameters as GCC expects it, namely a /* Create the list of the actual parameters as GCC expects it, namely a
chain of TREE_LIST nodes in which the TREE_VALUE field of each node chain of TREE_LIST nodes in which the TREE_VALUE field of each node
is an expression and the TREE_PURPOSE field is null. But skip Out is an expression and the TREE_PURPOSE field is null. But skip Out
...@@ -4469,12 +4463,10 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, ...@@ -4469,12 +4463,10 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target,
DECL_RETURN_VALUE_P (gnu_retval) = 1; DECL_RETURN_VALUE_P (gnu_retval) = 1;
} }
/* If we haven't pushed a binding level, push a new one. This will /* If we haven't pushed a binding level, push it now. This will
narrow the lifetime of the temporary we are about to make as much narrow the lifetime of the temporary we are about to make as
as possible. The drawback is that we'd need to create a temporary much as possible. */
for the return value, if any (see comment before the loop). So do if (!pushed_binding_level && (!returning_value || gnu_retval))
it only when this temporary was already created just above. */
if (!pushed_binding_level && !(in_param && returning_value))
{ {
start_stmt_group (); start_stmt_group ();
gnat_pushlevel (); gnat_pushlevel ();
...@@ -4705,15 +4697,6 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, ...@@ -4705,15 +4697,6 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target,
if (!gnu_retval) if (!gnu_retval)
{ {
tree gnu_stmt; tree gnu_stmt;
/* If we haven't pushed a binding level, push a new one. This
will narrow the lifetime of the temporary we are about to
make as much as possible. */
if (!pushed_binding_level)
{
start_stmt_group ();
gnat_pushlevel ();
pushed_binding_level = true;
}
gnu_call gnu_call
= create_init_temporary ("P", gnu_call, &gnu_stmt, gnat_node); = create_init_temporary ("P", gnu_call, &gnu_stmt, gnat_node);
append_to_statement_list (gnu_stmt, &gnu_stmt_list); append_to_statement_list (gnu_stmt, &gnu_stmt_list);
......
2016-02-29 Eric Botcazou <ebotcazou@adacore.com> 2016-02-29 Eric Botcazou <ebotcazou@adacore.com>
* gnat.dg/stack_usage3.adb: New test.
* gnat.dg/stack_usage3_pkg.ads: New helper.
2016-02-29 Eric Botcazou <ebotcazou@adacore.com>
* gnat.dg/renaming8.adb: New test. * gnat.dg/renaming8.adb: New test.
* gnat.dg/renaming8_pkg1.ads: New helper. * gnat.dg/renaming8_pkg1.ads: New helper.
* gnat.dg/renaming8_pkg2.ad[sb]: Likewise. * gnat.dg/renaming8_pkg2.ad[sb]: Likewise.
......
-- { dg-do compile }
-- { dg-options "-O -fstack-usage" }
with Ada.Text_IO; use Ada.Text_IO;
with Stack_Usage3_Pkg; use Stack_Usage3_Pkg;
procedure Stack_Usage3 is
begin
Put_Line (Diag ("Diag line 0"));
Put_Line (Diag ("Diag line 1"));
Put_Line (Diag ("Diag line 2"));
Put_Line (Diag ("Diag line 3"));
Put_Line (Diag ("Diag line 4"));
Put_Line (Diag ("Diag line 5"));
Put_Line (Diag ("Diag line 6"));
Put_Line (Diag ("Diag line 7"));
Put_Line (Diag ("Diag line 8"));
Put_Line (Diag ("Diag line 9"));
Put_Line (Diag ("Diag line 10"));
Put_Line (Diag ("Diag line 11"));
Put_Line (Diag ("Diag line 12"));
Put_Line (Diag ("Diag line 13"));
Put_Line (Diag ("Diag line 14"));
end;
-- { dg-final { scan-stack-usage "\t\[0-9\]\[0-9\]\t" { target i?86-*-* x86_64-*-* } } }
-- { dg-final { cleanup-stack-usage } }
package Stack_Usage3_Pkg is
subtype Small_String is String (1..80);
function Diag (S : String) return Small_String;
end Stack_Usage3_Pkg;
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