This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[tree-ssa] Nested functions


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);



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]