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]

Fix wrong code with complex nested functions tree


The new iterative algorithm that computes the need for static chains in nested 
functions trees has a flaw: it only detects changes of static chain setting 
in the function it has just processed.  So if a child function is nested in 
its parent and already requires a static chain, the parent is nested in the 
root function and doesn't, and the child function calls a sibling of its 
parent that does, the parent won't get the static chain it eventually needs 
because the setting is toggled from within the child function.

Fixed by computing the sum of the static chains in each nest and iterating 
until after it doesn't change.  Tested on x86-64-suse-linux, applied on the 
mainline and 4.5 branch as obvious.


2010-08-31  Eric Botcazou  <ebotcazou@adacore.com>

	* tree-nested.c (convert_all_function_calls): Iterate until after the
	sum of static chains in the nest doesn't change.


2010-08-31  Eric Botcazou  <ebotcazou@adacore.com>

	* gcc.dg/nested-func-8.c: New test.


-- 
Eric Botcazou
/* { dg-do run } */
/* { dg-options "-O -fno-inline" } */

extern void abort (void);

/* Return 0 and clobber the static chain.  */

int
zero (int n)
{
  int
  nested (int m)
  {
    return m - n;
  }

  return nested (n);
}

/* Return the triple of ARG in a convoluted manner.  */

int
triple (int arg)
{
  int
  read_arg (void)
  {
    return arg;
  }

  int
  parent (int nested_arg)
  {
    int
    child1 (void)
    {
      return parent (zero (5));
    }

    int
    child2 (void)
    {
      return nested_arg + read_arg ();
    }

    return (nested_arg == 0 ? 0 : child1 ()) + child2 ();
  }

  return parent (arg);
}

int main(void)
{
  if (triple (13) != 3 * 13)
    abort ();
  return 0;
}
Index: tree-nested.c
===================================================================
--- tree-nested.c	(revision 163659)
+++ tree-nested.c	(working copy)
@@ -2070,9 +2070,8 @@ convert_gimple_call (gimple_stmt_iterato
 static void
 convert_all_function_calls (struct nesting_info *root)
 {
+  unsigned int chain_count = 0, old_chain_count, iter_count;
   struct nesting_info *n;
-  int iter_count;
-  bool any_changed;
 
   /* First, optimistically clear static_chain for all decls that haven't
      used the static chain already for variable access.  */
@@ -2088,6 +2087,7 @@ convert_all_function_calls (struct nesti
 	}
       else
 	DECL_STATIC_CHAIN (decl) = 1;
+      chain_count += DECL_STATIC_CHAIN (decl);
     }
 
   /* Walk the functions and perform transformations.  Note that these
@@ -2100,7 +2100,8 @@ convert_all_function_calls (struct nesti
   iter_count = 0;
   do
     {
-      any_changed = false;
+      old_chain_count = chain_count;
+      chain_count = 0;
       iter_count++;
 
       if (dump_file && (dump_flags & TDF_DETAILS))
@@ -2109,22 +2110,16 @@ convert_all_function_calls (struct nesti
       FOR_EACH_NEST_INFO (n, root)
 	{
 	  tree decl = n->context;
-	  bool old_static_chain = DECL_STATIC_CHAIN (decl);
-
 	  walk_function (convert_tramp_reference_stmt,
 			 convert_tramp_reference_op, n);
 	  walk_function (convert_gimple_call, NULL, n);
-
-	  /* If a call to another function created the use of a chain
-	     within this function, we'll have to continue iteration.  */
-	  if (!old_static_chain && DECL_STATIC_CHAIN (decl))
-	    any_changed = true;
+	  chain_count += DECL_STATIC_CHAIN (decl);
 	}
     }
-  while (any_changed);
+  while (chain_count != old_chain_count);
 
   if (dump_file && (dump_flags & TDF_DETAILS))
-    fprintf (dump_file, "convert_all_function_calls iterations: %d\n\n",
+    fprintf (dump_file, "convert_all_function_calls iterations: %u\n\n",
 	     iter_count);
 }
 

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