Hi,

the compiler has had built-in support for nested functions for a long time, 
which makes it possible to support them in GNU C (as an extension) and in Ada; 
Fortran uses them too but marginally.  The support was entirely rewritten for 
GCC 4 and a few rough edges have remained since then, which are quite visible 
in languages where they are first-class citizens like Ada.

The first rough edge is the stack usage at -O0: it is twice as large as needed 
for variables subject to up-level references.  So you declare an array of 2KB 
bytes on the stack, factor out some code that reads it into a child function 
and then you suddenly need 4KB of stack instead of 2KB.  Even at -O0 this can 
be annoying for very embedded platforms.

The attached patch fixes it and also contains a tweak to use_pointer_in_frame 
for the sake of consistency but with no functional changes in practice.

Tested on x86-64/Linux, OK for the mainline?


2018-05-18  Eric Botcazou  <ebotca...@adacore.com>

        * tree-nested.c (use_pointer_in_frame): Tweak.
        (lookup_field_for_decl): Add assertion and declare the transformation.


2018-05-18  Eric Botcazou  <ebotca...@adacore.com>

        * gnat.dg/stack_usage5.adb: New test.

-- 
Eric Botcazou
Index: tree-nested.c
===================================================================
--- tree-nested.c	(revision 260239)
+++ tree-nested.c	(working copy)
@@ -236,23 +236,25 @@ get_frame_type (struct nesting_info *inf
   return type;
 }
 
-/* Return true if DECL should be referenced by pointer in the non-local
-   frame structure.  */
+/* Return true if DECL should be referenced by pointer in the non-local frame
+   structure.  */
 
 static bool
 use_pointer_in_frame (tree decl)
 {
   if (TREE_CODE (decl) == PARM_DECL)
     {
-      /* It's illegal to copy TREE_ADDRESSABLE, impossible to copy variable
-         sized decls, and inefficient to copy large aggregates.  Don't bother
-         moving anything but scalar variables.  */
+      /* It's illegal to copy TREE_ADDRESSABLE, impossible to copy variable-
+	 sized DECLs, and inefficient to copy large aggregates.  Don't bother
+	 moving anything but scalar parameters.  */
       return AGGREGATE_TYPE_P (TREE_TYPE (decl));
     }
   else
     {
-      /* Variable sized types make things "interesting" in the frame.  */
-      return DECL_SIZE (decl) == NULL || !TREE_CONSTANT (DECL_SIZE (decl));
+      /* Variable-sized DECLs can only come from OMP clauses at this point
+	 since the gimplifier has already turned the regular variables into
+	 pointers.  Do the same as the gimplifier.  */
+      return !DECL_SIZE (decl) || TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST;
     }
 }
 
@@ -263,6 +265,8 @@ static tree
 lookup_field_for_decl (struct nesting_info *info, tree decl,
 		       enum insert_option insert)
 {
+  gcc_checking_assert (decl_function_context (decl) == info->context);
+
   if (insert == NO_INSERT)
     {
       tree *slot = info->field_map->get (decl);
@@ -272,6 +276,7 @@ lookup_field_for_decl (struct nesting_in
   tree *slot = &info->field_map->get_or_insert (decl);
   if (!*slot)
     {
+      tree type = get_frame_type (info);
       tree field = make_node (FIELD_DECL);
       DECL_NAME (field) = DECL_NAME (decl);
 
@@ -290,9 +295,29 @@ lookup_field_for_decl (struct nesting_in
           TREE_ADDRESSABLE (field) = TREE_ADDRESSABLE (decl);
           DECL_NONADDRESSABLE_P (field) = !TREE_ADDRESSABLE (decl);
           TREE_THIS_VOLATILE (field) = TREE_THIS_VOLATILE (decl);
+
+	  /* Declare the transformation and adjust the original DECL.  */
+	  if (VAR_P (decl))
+	    {
+	      tree next = DECL_CHAIN (decl);
+	      tree x
+		= build3 (COMPONENT_REF, TREE_TYPE (field), info->frame_decl,
+			  field, NULL_TREE);
+	      SET_DECL_VALUE_EXPR (decl, x);
+	      DECL_HAS_VALUE_EXPR_P (decl) = 1;
+	      /* If the next declaration is a PARM_DECL pointing to the DECL,
+		 we need to adjust its VALUE_EXPR directly, since chains of
+		 VALUE_EXPRs run afoul of garbage collection.  This occurs
+		 in Ada for Out parameters that aren't copied in.  */
+	      if (next
+		  && TREE_CODE (next) == PARM_DECL
+		  && DECL_HAS_VALUE_EXPR_P (next)
+		  && DECL_VALUE_EXPR (next) == decl)
+		SET_DECL_VALUE_EXPR (next, x);
+	    }
 	}
 
-      insert_field_into_struct (get_frame_type (info), field);
+      insert_field_into_struct (type, field);
       *slot = field;
 
       if (TREE_CODE (decl) == PARM_DECL)
-- { dg-do compile }
-- { dg-options "-Wstack-usage=512" }

procedure Stack_Usage5 (C : Character) is

  S : String (1 .. 300);

  procedure Set is
  begin
    S (1) := C;
  end;

begin
  Set;
end;

Reply via email to