This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[tree-ssa] Nested functions
- From: law at redhat dot com
- To: gcc-patches at gcc dot gnu dot org
- Date: Thu, 01 May 2003 16:25:28 -0600
- Subject: [tree-ssa] Nested functions
- Reply-to: law at redhat dot com
This fixes a test I recently added to the tree-ssa branch (20030501-1.c).
In simplest terms a nested function can use variables in its parent
function which are in scope at the definition point of the nested
function.
This means that when we find a nested function, we need to mark all
variables at the same block nesting level as having a hidden use
(since they may be used by the nested function). We must also mark
all variables in the containing block nest as having a hidden use.
Whee fun. FWIW, there's other nasties in our handling of nested functions,
for example we can in some cases end up creating variables in the wrong
function.... Sigh...
* tree-dfa.c (find_hidden_use_vars): Renamed from find_vla_decls.
Now returns a value indicating if nested function was found.
When nested functions are found, mark suitable variables as
having hidden uses.
(find_hidden_use_vars_r): Renamed from find_vla_decls_r.
(compute_may_alias): Corresponding changes. Handle
multiple BLOCKs at the toplevel of a function.
Index: tree-dfa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-dfa.c,v
retrieving revision 1.1.4.103
diff -c -3 -p -r1.1.4.103 tree-dfa.c
*** tree-dfa.c 30 Apr 2003 18:55:38 -0000 1.1.4.103
--- tree-dfa.c 1 May 2003 22:02:18 -0000
*************** static void add_indirect_ref_var PARAMS
*** 137,144 ****
static void compute_immediate_uses_for PARAMS ((tree, int));
static void add_may_alias PARAMS ((tree, tree, tree, tree));
static bool call_may_clobber PARAMS ((tree));
! static void find_vla_decls PARAMS ((tree));
! static tree find_vla_decls_r PARAMS ((tree *, int *, void *));
/* Global declarations. */
--- 137,144 ----
static void compute_immediate_uses_for PARAMS ((tree, int));
static void add_may_alias PARAMS ((tree, tree, tree, tree));
static bool call_may_clobber PARAMS ((tree));
! static int find_hidden_use_vars PARAMS ((tree));
! static tree find_hidden_use_vars_r PARAMS ((tree *, int *, void *));
/* Global declarations. */
*************** compute_may_aliases (fndecl)
*** 1651,1664 ****
basic_block bb;
block_stmt_iterator si;
struct walk_state walk_state;
timevar_push (TV_TREE_MAY_ALIAS);
/* Walk the lexical blocks in the function looking for variables that may
! have been used to declare VLAs. Those variables will be considered
! implicitly live by passes like DCE. FIXME: This is a hack. GIMPLE
! should expose VLAs in the code. */
! find_vla_decls (DECL_INITIAL (fndecl));
num_aliased_objects = 0;
VARRAY_TREE_INIT (aliased_objects, 20, "aliased_objects");
--- 1651,1673 ----
basic_block bb;
block_stmt_iterator si;
struct walk_state walk_state;
+ tree block;
timevar_push (TV_TREE_MAY_ALIAS);
/* Walk the lexical blocks in the function looking for variables that may
! have been used to declare VLAs and for nested functions. Both
! constructs create hidden uses of variables.
!
! Note that at this point we may have multiple blocks hung off
! DECL_INITIAL chained through the BLOCK_CHAIN field due to
! how inlining works. Egad. */
! block = DECL_INITIAL (fndecl);
! while (block)
! {
! find_hidden_use_vars (block);
! block = BLOCK_CHAIN (block);
! }
num_aliased_objects = 0;
VARRAY_TREE_INIT (aliased_objects, 20, "aliased_objects");
*************** call_may_clobber (expr)
*** 2539,2575 ****
}
! /* Mark variables that are being used to declare VLAs (Variable Length
! Arrays). Those variables will be considered implicitly live by the
! dataflow routines. FIXME: This is a huge ugly hack. GIMPLE should
! expose VLAs more gracefully. */
! static void
! find_vla_decls (block)
tree block;
{
tree sub, decl;
! /* Check all the arrays declared in the block. */
for (decl = BLOCK_VARS (block); decl; decl = TREE_CHAIN (decl))
{
int inside_vla = 0;
! walk_tree (&decl, find_vla_decls_r, &inside_vla, NULL);
}
/* Now repeat the search in any sub-blocks. */
for (sub = BLOCK_SUBBLOCKS (block); sub; sub = TREE_CHAIN (sub))
! find_vla_decls (sub);
! }
! /* Callback for walk_tree used by find_vla_decls to analyze each array in a
! lexical block. For each array type, it walks its TYPE_SIZE and
TYPE_SIZE_UNIT trees looking for VAR_DECLs. Those VAR_DECLs will be
marked as having a hidden use. */
static tree
! find_vla_decls_r (tp, walk_subtrees, data)
tree *tp;
int *walk_subtrees ATTRIBUTE_UNUSED;
void *data ATTRIBUTE_UNUSED;
--- 2548,2608 ----
}
! /* Mark variables that have hidden uses.
! A hidden use can occur due to VLA declarations or nested functions.
!
! Return nonzero if we found a nested function at this block's
! depth or in one of its children (recursively). */
!
! static int
! find_hidden_use_vars (block)
tree block;
{
tree sub, decl;
+ int found_nested_function = 0;
+
+ /* Check all the arrays declared in the block for VLAs.
! While scanning the block's variables, also see if there is
! a nested function at this scope. */
for (decl = BLOCK_VARS (block); decl; decl = TREE_CHAIN (decl))
{
int inside_vla = 0;
!
! /* Note if we saw a nested function. */
! if (TREE_CODE (decl) == FUNCTION_DECL)
! found_nested_function = 1;
!
! walk_tree (&decl, find_hidden_use_vars_r, &inside_vla, NULL);
}
/* Now repeat the search in any sub-blocks. */
for (sub = BLOCK_SUBBLOCKS (block); sub; sub = TREE_CHAIN (sub))
! found_nested_function |= find_hidden_use_vars (sub);
+ /* If this scope or one of its children has a nested function,
+ then we have to mark all the variables at this block's scope
+ as having a hidden use and propagate that information up the
+ block scope tree. */
+ if (found_nested_function)
+ {
+ for (decl = BLOCK_VARS (block); decl; decl = TREE_CHAIN (decl))
+ if (TREE_CODE (decl) == VAR_DECL)
+ set_has_hidden_use (decl);
+ return 1;
+ }
+
+ return 0;
+ }
! /* Callback for walk_tree used by find_hidden_use_vars to analyze each array
! in a lexical block. For each array type, it walks its TYPE_SIZE and
TYPE_SIZE_UNIT trees looking for VAR_DECLs. Those VAR_DECLs will be
marked as having a hidden use. */
static tree
! find_hidden_use_vars_r (tp, walk_subtrees, data)
tree *tp;
int *walk_subtrees ATTRIBUTE_UNUSED;
void *data ATTRIBUTE_UNUSED;
*************** find_vla_decls_r (tp, walk_subtrees, dat
*** 2579,2586 ****
if (TREE_CODE (*tp) == ARRAY_TYPE)
{
*inside_vla = 1;
! walk_tree (&TYPE_SIZE (*tp), find_vla_decls_r, inside_vla, NULL);
! walk_tree (&TYPE_SIZE_UNIT (*tp), find_vla_decls_r, inside_vla, NULL);
}
else if (*inside_vla && SSA_DECL_P (*tp))
set_has_hidden_use (*tp);
--- 2612,2620 ----
if (TREE_CODE (*tp) == ARRAY_TYPE)
{
*inside_vla = 1;
! walk_tree (&TYPE_SIZE (*tp), find_hidden_use_vars_r, inside_vla, NULL);
! walk_tree (&TYPE_SIZE_UNIT (*tp), find_hidden_use_vars_r,
! inside_vla, NULL);
}
else if (*inside_vla && SSA_DECL_P (*tp))
set_has_hidden_use (*tp);