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;