trans.c (finalize_nrv_r): Remove obsolete code.
authorEric Botcazou <ebotcazou@adacore.com>
Mon, 29 Feb 2016 09:16:57 +0000 (09:16 +0000)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Mon, 29 Feb 2016 09:16:57 +0000 (09:16 +0000)
* 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

gcc/ada/ChangeLog
gcc/ada/gcc-interface/trans.c
gcc/testsuite/ChangeLog
gcc/testsuite/gnat.dg/stack_usage3.adb [new file with mode: 0644]
gcc/testsuite/gnat.dg/stack_usage3_pkg.ads [new file with mode: 0644]

index 49c0632ef043ff00420dd68cb03c73cba5d296e4..9fcf75ccf6e476c4263584e641ef7e2ea72d6599 100644 (file)
@@ -1,3 +1,12 @@
+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.
index f830a3d24900da16d4d131f5f1986432bae300d0..c78b01b177afd58261fc54a850b10e985b1bc07e 100644 (file)
@@ -3330,32 +3330,14 @@ finalize_nrv_r (tree *tp, int *walk_subtrees, void *data)
   else if (TREE_CODE (t) == RETURN_EXPR
           && TREE_CODE (TREE_OPERAND (t, 0)) == INIT_EXPR)
     {
-      tree ret_val = TREE_OPERAND (TREE_OPERAND (t, 0), 1), init_expr;
-
-      /* 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;
+      tree ret_val = TREE_OPERAND (TREE_OPERAND (t, 0), 1);
 
       /* Strip useless conversions around the return value.  */
       if (gnat_useless_type_conversion (ret_val))
        ret_val = TREE_OPERAND (ret_val, 0);
 
       if (is_nrv_p (dp->nrv, ret_val))
-       {
-         if (init_expr)
-           TREE_OPERAND (TREE_OPERAND (t, 0), 1) = init_expr;
-         else
-           TREE_OPERAND (t, 0) = dp->result;
-       }
+       TREE_OPERAND (t, 0) = dp->result;
     }
 
   /* 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)
          && TYPE_MODE (operation_type) == BLKmode
          && 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.  */
          if (gnat_useless_type_conversion (ret_val))
            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,
          because we need to preserve the return value before copying back the
          parameters.
 
-       2. There is no target and this is neither an object nor a renaming
-         declaration, and the return type has variable size, because in
-         these cases the gimplifier cannot create the temporary.
+       2. There is no target and the call is made for neither an object nor a
+         renaming declaration, nor a return statement, and the return type has
+         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,
          and the return type has variable size, because the gimplifier
          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
      we will pop it before copying the return value.  */
   if (function_call
@@ -4329,7 +4311,9 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target,
          || (!gnu_target
              && Nkind (Parent (gnat_node)) != N_Object_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
              && (TREE_CODE (gnu_target) == ARRAY_RANGE_REF
                  || (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,
       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
      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
@@ -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;
            }
 
-         /* 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.  The drawback is that we'd need to create a temporary
-            for the return value, if any (see comment before the loop).  So do
-            it only when this temporary was already created just above.  */
-         if (!pushed_binding_level && !(in_param && returning_value))
+         /* 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 as possible.  */
+         if (!pushed_binding_level && (!returning_value || gnu_retval))
            {
              start_stmt_group ();
              gnat_pushlevel ();
@@ -4705,15 +4697,6 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target,
          if (!gnu_retval)
            {
              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
                = create_init_temporary ("P", gnu_call, &gnu_stmt, gnat_node);
              append_to_statement_list (gnu_stmt, &gnu_stmt_list);
index d6803dabd7481808cc2ad4110ab6ee9287bd583a..4e85314e00bcf1a61088a6d7d417f189e9a21c65 100644 (file)
@@ -1,3 +1,8 @@
+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.
diff --git a/gcc/testsuite/gnat.dg/stack_usage3.adb b/gcc/testsuite/gnat.dg/stack_usage3.adb
new file mode 100644 (file)
index 0000000..fcc5cac
--- /dev/null
@@ -0,0 +1,28 @@
+-- { 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 } }
diff --git a/gcc/testsuite/gnat.dg/stack_usage3_pkg.ads b/gcc/testsuite/gnat.dg/stack_usage3_pkg.ads
new file mode 100644 (file)
index 0000000..e4a80c3
--- /dev/null
@@ -0,0 +1,7 @@
+package Stack_Usage3_Pkg is
+
+   subtype Small_String is String (1..80);
+
+   function Diag (S : String) return Small_String;
+
+end Stack_Usage3_Pkg;