Patchwork Fortran frontend walker

login
register
mail settings
Submitter Jakub Jelinek
Date Sept. 15, 2010, 6:31 p.m.
Message ID <20100915183152.GO1269@tyan-ft48-01.lab.bos.redhat.com>
Download mbox | patch
Permalink /patch/64882/
State New
Headers show

Comments

Jakub Jelinek - Sept. 15, 2010, 6:31 p.m.
Hi!

On Tue, Sep 14, 2010 at 04:37:14PM +0200, Jakub Jelinek wrote:
> On Tue, Sep 14, 2010 at 12:08:12AM +0200, Mikael Morin wrote:
> I meant something like:

Here are two possible patches, which add the walker and
convert optimize_namespace to use it.

The difference between the two patches is that the first patch
passes around address of gfc_code * or gfc_expr *, so it is possible to
change it easily, while the latter passes around gfc_code * or
gfc_expr *.  In all the changes I've looked at the simplifications were done
by adjusting fields in gfc_expr (possible turning it into different type
and changing its arguments), so perhaps the second patch might be
sufficient.

So far tested just by make check-gfortran and make check -C libgomp,
don't want to bootstrap both versions...

	Jakub
2010-09-15  Jakub Jelinek  <jakub@redhat.com>

	* gfortran.h (walk_code_fn_t, walk_expr_fn_t): New types.
	(gfc_expr_walker, gfc_code_walker): New prototypes.
	* frontend-passes.c (gfc_expr_walker, gfc_code_walker): New functions.
	(WALK_SUBEXPR, WALK_SUBEXPR_TAIL, WALK_SUBCODE): Define.
	(optimize_namespace): Use gfc_code_walker.
	(optimize_code, optimize_expr): Rewritten as gfc_code_walker hooks.
	(optimize_expr_0, optimize_code_node,
	optimize_actual_arglist): Removed.
	(optimize_assignment): Don't call optimize_expr_0.
2010-09-15  Jakub Jelinek  <jakub@redhat.com>

	* gfortran.h (walk_code_fn_t, walk_expr_fn_t): New types.
	(gfc_expr_walker, gfc_code_walker): New prototypes.
	* frontend-passes.c (gfc_expr_walker, gfc_code_walker): New functions.
	(WALK_SUBEXPR, WALK_SUBEXPR_TAIL, WALK_SUBCODE): Define.
	(optimize_namespace): Use gfc_code_walker.
	(optimize_code, optimize_expr): Rewritten as gfc_code_walker hooks.
	(optimize_expr_0, optimize_code_node,
	optimize_actual_arglist): Removed.
	(optimize_assignment): Don't call optimize_expr_0.

--- gcc/fortran/gfortran.h.jj	2010-09-14 15:24:43.000000000 +0200
+++ gcc/fortran/gfortran.h	2010-09-15 19:53:00.000000000 +0200
@@ -2886,4 +2886,10 @@ gfc_symtree* gfc_get_tbp_symtree (gfc_sy
 
 void gfc_run_passes (gfc_namespace *);
 
+typedef int (*walk_code_fn_t) (gfc_code *, int *, void *);
+typedef int (*walk_expr_fn_t) (gfc_expr *, int *, void *);
+
+int gfc_expr_walker (gfc_expr *, walk_expr_fn_t, void *);
+int gfc_code_walker (gfc_code *, walk_code_fn_t, walk_expr_fn_t, void *);
+
 #endif /* GCC_GFORTRAN_H  */
--- gcc/fortran/frontend-passes.c.jj	2010-09-14 15:24:26.000000000 +0200
+++ gcc/fortran/frontend-passes.c	2010-09-15 20:19:52.000000000 +0200
@@ -30,13 +30,8 @@ along with GCC; see the file COPYING3.  
 static void strip_function_call (gfc_expr *);
 static void optimize_namespace (gfc_namespace *);
 static void optimize_assignment (gfc_code *);
-static void optimize_expr_0 (gfc_expr *);
-static bool optimize_expr (gfc_expr *);
 static bool optimize_op (gfc_expr *);
 static bool optimize_equality (gfc_expr *, bool);
-static void optimize_code (gfc_code *);
-static void optimize_code_node (gfc_code *);
-static void optimize_actual_arglist (gfc_actual_arglist *);
 
 /* Entry point - run all passes for a namespace.  So far, only an
    optimization pass is run.  */
@@ -48,195 +43,39 @@ gfc_run_passes (gfc_namespace *ns)
     optimize_namespace (ns);
 }
 
-/* Optimize a namespace, including all contained namespaces.  */
+/* Callback for each gfc_code node invoked through gfc_code_walker
+   from optimize_namespace.  */
 
-static void
-optimize_namespace (gfc_namespace *ns)
+static int
+optimize_code (gfc_code *c, int *walk_subtrees ATTRIBUTE_UNUSED,
+	       void *data ATTRIBUTE_UNUSED)
 {
-  optimize_code (ns->code);
-
-  for (ns = ns->contained; ns; ns = ns->sibling)
-    optimize_namespace (ns);
+  if (c->op == EXEC_ASSIGN)
+    optimize_assignment (c);
+  return 0;
 }
 
-static void
-optimize_code (gfc_code *c)
+/* Callback for each gfc_expr node invoked through gfc_code_walker
+   from optimize_namespace.  */
+
+static int
+optimize_expr (gfc_expr *e, int *walk_subtrees ATTRIBUTE_UNUSED,
+	       void *data ATTRIBUTE_UNUSED)
 {
-  for (; c; c = c->next)
-    optimize_code_node (c);
+  if (e->expr_type == EXPR_OP && optimize_op (e))
+    gfc_simplify_expr (e, 0);
+  return 0;
 }
 
-
-/* Do the optimizations for a code node.  */
+/* Optimize a namespace, including all contained namespaces.  */
 
 static void
-optimize_code_node (gfc_code *c)
+optimize_namespace (gfc_namespace *ns)
 {
+  gfc_code_walker (ns->code, optimize_code, optimize_expr, NULL);
 
-  gfc_forall_iterator *fa;
-  gfc_code *d;
-  gfc_alloc *a;
-
-  switch (c->op)
-    {
-    case EXEC_ASSIGN:
-      optimize_assignment (c);
-      break;
-
-    case EXEC_CALL:
-    case EXEC_ASSIGN_CALL:
-    case EXEC_CALL_PPC:
-      optimize_actual_arglist (c->ext.actual);
-      break;
-
-    case EXEC_ARITHMETIC_IF:
-      optimize_expr_0 (c->expr1);
-      break;
-
-    case EXEC_PAUSE:
-    case EXEC_RETURN:
-    case EXEC_ERROR_STOP:
-    case EXEC_STOP:
-    case EXEC_COMPCALL:
-      optimize_expr_0 (c->expr1);
-      break;
-
-    case EXEC_SYNC_ALL:
-    case EXEC_SYNC_MEMORY:
-    case EXEC_SYNC_IMAGES:
-      optimize_expr_0 (c->expr2);
-      break;
-
-    case EXEC_IF:
-      d = c->block;
-      optimize_expr_0 (d->expr1);
-      optimize_code (d->next);
-
-      for (d = d->block; d; d = d->block)
-	{
-	  optimize_expr_0 (d->expr1);
-
-	  optimize_code (d->next);
-	}
-
-
-      break;
-
-    case EXEC_SELECT:
-    case EXEC_SELECT_TYPE:
-      d = c->block;
-
-      optimize_expr_0 (c->expr1);
-
-      for (; d; d = d->block)
-	optimize_code (d->next);
-
-      break;
-
-    case EXEC_WHERE:
-      d = c->block;
-      optimize_expr_0 (d->expr1);
-      optimize_code (d->next);
-
-      for (d = d->block; d; d = d->block)
-	{
-	  optimize_expr_0 (d->expr1);
-	  optimize_code (d->next);
-	}
-      break;
-
-    case EXEC_FORALL:
-
-      for (fa = c->ext.forall_iterator; fa; fa = fa->next)
-	{
-	  optimize_expr_0 (fa->start);
-	  optimize_expr_0 (fa->end);
-	  optimize_expr_0 (fa->stride);
-	}
-
-      if (c->expr1 != NULL)
-	  optimize_expr_0 (c->expr1);
-
-      optimize_code (c->block->next);
-
-      break;
-
-    case EXEC_CRITICAL:
-      optimize_code (c->block->next);
-      break;
-
-    case EXEC_DO:
-      optimize_expr_0 (c->ext.iterator->start);
-      optimize_expr_0 (c->ext.iterator->end);
-      optimize_expr_0 (c->ext.iterator->step);
-      optimize_code (c->block->next);
-
-      break;
-
-    case EXEC_DO_WHILE:
-      optimize_expr_0 (c->expr1);
-      optimize_code (c->block->next);
-      break;
-
-
-    case EXEC_ALLOCATE:
-      for (a = c->ext.alloc.list; a; a = a->next)
-	  optimize_expr_0 (a->expr);
-      break;
-
-      /* Todo:  Some of these may need to be optimized, as well.  */
-    case EXEC_WRITE:
-    case EXEC_READ:
-    case EXEC_OPEN:
-    case EXEC_INQUIRE:
-    case EXEC_REWIND:
-    case EXEC_ENDFILE:
-    case EXEC_BACKSPACE:
-    case EXEC_CLOSE:
-    case EXEC_WAIT:
-    case EXEC_TRANSFER:
-    case EXEC_FLUSH:
-    case EXEC_IOLENGTH:
-    case EXEC_END_PROCEDURE:
-    case EXEC_NOP:
-    case EXEC_CONTINUE:
-    case EXEC_ENTRY:
-    case EXEC_INIT_ASSIGN:
-    case EXEC_LABEL_ASSIGN:
-    case EXEC_POINTER_ASSIGN:
-    case EXEC_GOTO:
-    case EXEC_CYCLE:
-    case EXEC_EXIT:
-    case EXEC_BLOCK:
-    case EXEC_END_BLOCK:
-    case EXEC_OMP_ATOMIC:
-    case EXEC_OMP_BARRIER:
-    case EXEC_OMP_CRITICAL:
-    case EXEC_OMP_FLUSH:
-    case EXEC_OMP_DO:
-    case EXEC_OMP_MASTER:
-    case EXEC_OMP_ORDERED:
-    case EXEC_OMP_PARALLEL:
-    case EXEC_OMP_PARALLEL_DO:
-    case EXEC_OMP_PARALLEL_SECTIONS:
-    case EXEC_OMP_PARALLEL_WORKSHARE:
-    case EXEC_OMP_SECTIONS:
-    case EXEC_OMP_SINGLE:
-    case EXEC_OMP_TASK:
-    case EXEC_OMP_TASKWAIT:
-    case EXEC_OMP_WORKSHARE:
-    case EXEC_OMP_END_NOWAIT:
-    case EXEC_OMP_END_SINGLE:
-    case EXEC_DEALLOCATE:
-    case EXEC_DT_END:
-      for (d = c->block; d; d = d->block)
-	optimize_code (d->next);
-      break;
-
-    default:
-      gcc_unreachable ();
-
-    }
+  for (ns = ns->contained; ns; ns = ns->sibling)
+    optimize_namespace (ns);
 }
 
 /* Replace code like
@@ -336,15 +175,6 @@ optimize_assignment (gfc_code * c)
 
   if (lhs->rank > 0 && gfc_check_dependency (lhs, rhs, true) == 0)
     optimize_binop_array_assignment (c, &rhs, false);
-
-  /* If we insert a statement after the current one, the surrounding loop in
-     optimize_code will call optimize_assignment on the inserted statement
-     anyway, so there is no need to call optimize_assignment again.  */
-
-  /* All direct optimizations have been done.  Now it's time
-     to optimize the rhs.  */
-
-  optimize_expr_0 (rhs);
 }
 
 
@@ -375,58 +205,12 @@ strip_function_call (gfc_expr *e)
 
 }
 
-/* Top-level optimization of expressions.  Calls gfc_simplify_expr if
-   optimize_expr succeeds in doing something.
-   TODO: Optimization of multiple function occurrence to come here.  */
-
-static void
-optimize_expr_0 (gfc_expr * e)
-{
-  if (optimize_expr (e))
-    gfc_simplify_expr (e, 0);
-
-  return;
-}
-
-/* Recursive optimization of expressions.
- TODO:  Make this handle many more things.  */
-
-static bool
-optimize_expr (gfc_expr *e)
-{
-  bool ret;
-
-  if (e == NULL)
-    return false;
-
-  ret = false;
-
-  switch (e->expr_type)
-    {
-    case EXPR_OP:
-      return optimize_op (e);
-      break;
-
-    case EXPR_FUNCTION:
-      optimize_actual_arglist (e->value.function.actual);
-      break;
-
-    default:
-      break;
-    }
-
-  return ret;
-}
-
 /* Recursive optimization of operators.  */
 
 static bool
 optimize_op (gfc_expr *e)
 {
-
-  gfc_intrinsic_op op;
-
-  op = e->value.op.op;
+  gfc_intrinsic_op op = e->value.op.op;
 
   switch (op)
     {
@@ -437,7 +221,6 @@ optimize_op (gfc_expr *e)
     case INTRINSIC_LE:
     case INTRINSIC_LE_OS:
       return optimize_equality (e, true);
-      break;
 
     case INTRINSIC_NE:
     case INTRINSIC_NE_OS:
@@ -446,7 +229,6 @@ optimize_op (gfc_expr *e)
     case INTRINSIC_LT:
     case INTRINSIC_LT_OS:
       return optimize_equality (e, false);
-      break;
 
     default:
       break;
@@ -460,7 +242,6 @@ optimize_op (gfc_expr *e)
 static bool
 optimize_equality (gfc_expr *e, bool equal)
 {
-
   gfc_expr *op1, *op2;
   bool change;
 
@@ -519,18 +300,252 @@ optimize_equality (gfc_expr *e, bool equ
   return false;
 }
 
-/* Optimize a call list.  Right now, this just goes through the actual
-   arg list and optimizes each expression in turn.  */
-
-static void
-optimize_actual_arglist (gfc_actual_arglist *a)
+#define WALK_SUBEXPR(NODE) \
+  do							\
+    {							\
+      result = gfc_expr_walker ((NODE), exprfn, data);	\
+      if (result)					\
+	return result;					\
+    }							\
+  while (0)
+#define WALK_SUBEXPR_TAIL(NODE) e = (NODE); continue
+
+/* Walk expression E, calling EXPRFN on each expression in it.  */
+
+int
+gfc_expr_walker (gfc_expr *e, walk_expr_fn_t exprfn, void *data)
+{
+  while (e)
+    {
+      int walk_subtrees = 1;
+      gfc_actual_arglist *a;
+      int result = exprfn (e, &walk_subtrees, data);
+      if (result)
+	return result;
+      if (walk_subtrees)
+	switch (e->expr_type)
+	  {
+	  case EXPR_OP:
+	    WALK_SUBEXPR (e->value.op.op1);
+	    WALK_SUBEXPR_TAIL (e->value.op.op2);
+	    break;
+	  case EXPR_FUNCTION:
+	    for (a = e->value.function.actual; a; a = a->next)
+	      WALK_SUBEXPR (a->expr);
+	    break;
+	  case EXPR_COMPCALL:
+	  case EXPR_PPC:
+	    WALK_SUBEXPR (e->value.compcall.base_object);
+	    for (a = e->value.compcall.actual; a; a = a->next)
+	      WALK_SUBEXPR (a->expr);
+	    break;
+	  default:
+	    break;
+	  }
+      return 0;
+    }
+  return 0;
+}
+
+#define WALK_SUBCODE(NODE) \
+  do								\
+    {								\
+      result = gfc_code_walker ((NODE), codefn, exprfn, data);	\
+      if (result)						\
+	return result;						\
+    }								\
+  while (0)
+
+/* Walk code C, calling CODEFN on each gfc_code node in it and calling EXPRFN
+   on each expression in it.  If any of the hooks returns non-zero, that
+   value is immediately returned.  If the hook sets *WALK_SUBTREES to 0,
+   no subcodes or subexpressions are traversed.  */
+
+int
+gfc_code_walker (gfc_code *c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
+		 void *data)
 {
-
-  for (; a; a = a->next)
+  for (; c; c = c->next)
     {
-      if (a->expr != NULL)
-	optimize_expr_0 (a->expr);
+      int walk_subtrees = 1;
+      int result = codefn (c, &walk_subtrees, data);
+      if (result)
+	return result;
+      if (walk_subtrees)
+	{
+	  gfc_code *b;
+	  switch (c->op)
+	    {
+	    case EXEC_DO:
+	      WALK_SUBEXPR (c->ext.iterator->var);
+	      WALK_SUBEXPR (c->ext.iterator->start);
+	      WALK_SUBEXPR (c->ext.iterator->end);
+	      WALK_SUBEXPR (c->ext.iterator->step);
+	      break;
+	    case EXEC_SELECT:
+	      WALK_SUBEXPR (c->expr1);
+	      for (b = c->block; b; b = b->block)
+		{
+		  gfc_case *cp;
+		  for (cp = b->ext.case_list; cp; cp = cp->next)
+		    {
+		      WALK_SUBEXPR (cp->low);
+		      WALK_SUBEXPR (cp->high);
+		    }
+		  WALK_SUBCODE (b->next);
+		}
+	      continue;
+	    case EXEC_ALLOCATE:
+	    case EXEC_DEALLOCATE:
+	      {
+		gfc_alloc *a;
+		for (a = c->ext.alloc.list; a; a = a->next)
+		  WALK_SUBEXPR (a->expr);
+		break;
+	      }
+	    case EXEC_FORALL:
+	      {
+		gfc_forall_iterator *fa;
+		for (fa = c->ext.forall_iterator; fa; fa = fa->next)
+		  {
+		    WALK_SUBEXPR (fa->var);
+		    WALK_SUBEXPR (fa->start);
+		    WALK_SUBEXPR (fa->end);
+		    WALK_SUBEXPR (fa->stride);
+		  }
+		break;
+	      }
+	    case EXEC_OPEN:
+	      WALK_SUBEXPR (c->ext.open->unit);
+	      WALK_SUBEXPR (c->ext.open->file);
+	      WALK_SUBEXPR (c->ext.open->status);
+	      WALK_SUBEXPR (c->ext.open->access);
+	      WALK_SUBEXPR (c->ext.open->form);
+	      WALK_SUBEXPR (c->ext.open->recl);
+	      WALK_SUBEXPR (c->ext.open->blank);
+	      WALK_SUBEXPR (c->ext.open->position);
+	      WALK_SUBEXPR (c->ext.open->action);
+	      WALK_SUBEXPR (c->ext.open->delim);
+	      WALK_SUBEXPR (c->ext.open->pad);
+	      WALK_SUBEXPR (c->ext.open->iostat);
+	      WALK_SUBEXPR (c->ext.open->iomsg);
+	      WALK_SUBEXPR (c->ext.open->convert);
+	      WALK_SUBEXPR (c->ext.open->decimal);
+	      WALK_SUBEXPR (c->ext.open->encoding);
+	      WALK_SUBEXPR (c->ext.open->round);
+	      WALK_SUBEXPR (c->ext.open->sign);
+	      WALK_SUBEXPR (c->ext.open->asynchronous);
+	      WALK_SUBEXPR (c->ext.open->id);
+	      WALK_SUBEXPR (c->ext.open->newunit);
+	      break;
+	    case EXEC_CLOSE:
+	      WALK_SUBEXPR (c->ext.close->unit);
+	      WALK_SUBEXPR (c->ext.close->status);
+	      WALK_SUBEXPR (c->ext.close->iostat);
+	      WALK_SUBEXPR (c->ext.close->iomsg);
+	      break;
+	    case EXEC_BACKSPACE:
+	    case EXEC_ENDFILE:
+	    case EXEC_REWIND:
+	    case EXEC_FLUSH:
+	      WALK_SUBEXPR (c->ext.filepos->unit);
+	      WALK_SUBEXPR (c->ext.filepos->iostat);
+	      WALK_SUBEXPR (c->ext.filepos->iomsg);
+	      break;
+	    case EXEC_INQUIRE:
+	      WALK_SUBEXPR (c->ext.inquire->unit);
+	      WALK_SUBEXPR (c->ext.inquire->file);
+	      WALK_SUBEXPR (c->ext.inquire->iomsg);
+	      WALK_SUBEXPR (c->ext.inquire->iostat);
+	      WALK_SUBEXPR (c->ext.inquire->exist);
+	      WALK_SUBEXPR (c->ext.inquire->opened);
+	      WALK_SUBEXPR (c->ext.inquire->number);
+	      WALK_SUBEXPR (c->ext.inquire->named);
+	      WALK_SUBEXPR (c->ext.inquire->name);
+	      WALK_SUBEXPR (c->ext.inquire->access);
+	      WALK_SUBEXPR (c->ext.inquire->sequential);
+	      WALK_SUBEXPR (c->ext.inquire->direct);
+	      WALK_SUBEXPR (c->ext.inquire->form);
+	      WALK_SUBEXPR (c->ext.inquire->formatted);
+	      WALK_SUBEXPR (c->ext.inquire->unformatted);
+	      WALK_SUBEXPR (c->ext.inquire->recl);
+	      WALK_SUBEXPR (c->ext.inquire->nextrec);
+	      WALK_SUBEXPR (c->ext.inquire->blank);
+	      WALK_SUBEXPR (c->ext.inquire->position);
+	      WALK_SUBEXPR (c->ext.inquire->action);
+	      WALK_SUBEXPR (c->ext.inquire->read);
+	      WALK_SUBEXPR (c->ext.inquire->write);
+	      WALK_SUBEXPR (c->ext.inquire->readwrite);
+	      WALK_SUBEXPR (c->ext.inquire->delim);
+	      WALK_SUBEXPR (c->ext.inquire->encoding);
+	      WALK_SUBEXPR (c->ext.inquire->pad);
+	      WALK_SUBEXPR (c->ext.inquire->iolength);
+	      WALK_SUBEXPR (c->ext.inquire->convert);
+	      WALK_SUBEXPR (c->ext.inquire->strm_pos);
+	      WALK_SUBEXPR (c->ext.inquire->asynchronous);
+	      WALK_SUBEXPR (c->ext.inquire->decimal);
+	      WALK_SUBEXPR (c->ext.inquire->pending);
+	      WALK_SUBEXPR (c->ext.inquire->id);
+	      WALK_SUBEXPR (c->ext.inquire->sign);
+	      WALK_SUBEXPR (c->ext.inquire->size);
+	      WALK_SUBEXPR (c->ext.inquire->round);
+	      break;
+	    case EXEC_WAIT:
+	      WALK_SUBEXPR (c->ext.wait->unit);
+	      WALK_SUBEXPR (c->ext.wait->iostat);
+	      WALK_SUBEXPR (c->ext.wait->iomsg);
+	      WALK_SUBEXPR (c->ext.wait->id);
+	      break;
+	    case EXEC_READ:
+	    case EXEC_WRITE:
+	      WALK_SUBEXPR (c->ext.dt->io_unit);
+	      WALK_SUBEXPR (c->ext.dt->format_expr);
+	      WALK_SUBEXPR (c->ext.dt->rec);
+	      WALK_SUBEXPR (c->ext.dt->advance);
+	      WALK_SUBEXPR (c->ext.dt->iostat);
+	      WALK_SUBEXPR (c->ext.dt->size);
+	      WALK_SUBEXPR (c->ext.dt->iomsg);
+	      WALK_SUBEXPR (c->ext.dt->id);
+	      WALK_SUBEXPR (c->ext.dt->pos);
+	      WALK_SUBEXPR (c->ext.dt->asynchronous);
+	      WALK_SUBEXPR (c->ext.dt->blank);
+	      WALK_SUBEXPR (c->ext.dt->decimal);
+	      WALK_SUBEXPR (c->ext.dt->delim);
+	      WALK_SUBEXPR (c->ext.dt->pad);
+	      WALK_SUBEXPR (c->ext.dt->round);
+	      WALK_SUBEXPR (c->ext.dt->sign);
+	      WALK_SUBEXPR (c->ext.dt->extra_comma);
+	      break;
+	    case EXEC_OMP_DO:
+	    case EXEC_OMP_PARALLEL:
+	    case EXEC_OMP_PARALLEL_DO:
+	    case EXEC_OMP_PARALLEL_SECTIONS:
+	    case EXEC_OMP_PARALLEL_WORKSHARE:
+	    case EXEC_OMP_SECTIONS:
+	    case EXEC_OMP_SINGLE:
+	    case EXEC_OMP_WORKSHARE:
+	    case EXEC_OMP_END_SINGLE:
+	    case EXEC_OMP_TASK:
+	      if (c->ext.omp_clauses)
+		{
+		  WALK_SUBEXPR (c->ext.omp_clauses->if_expr);
+		  WALK_SUBEXPR (c->ext.omp_clauses->num_threads);
+		  WALK_SUBEXPR (c->ext.omp_clauses->chunk_size);
+		}
+	      break;
+	    default:
+	      break;
+	    }
+	  WALK_SUBEXPR (c->expr1);
+	  WALK_SUBEXPR (c->expr2);
+	  WALK_SUBEXPR (c->expr3);
+	  for (b = c->block; b; b = b->block)
+	    {
+	      WALK_SUBEXPR (b->expr1);
+	      WALK_SUBEXPR (b->expr2);
+	      WALK_SUBCODE (b->next);
+	    }
+	}
     }
-  
-  return;
+  return 0;
 }
Thomas Koenig - Sept. 15, 2010, 9:12 p.m.
Hi Jakub,


> Here are two possible patches, which add the walker and
> convert optimize_namespace to use it.
> 
> The difference between the two patches is that the first patch
> passes around address of gfc_code * or gfc_expr *, so it is possible to
> change it easily, while the latter passes around gfc_code * or
> gfc_expr *.  In all the changes I've looked at the simplifications were done
> by adjusting fields in gfc_expr (possible turning it into different type
> and changing its arguments), so perhaps the second patch might be
> sufficient.

Two remarks:

1. I see you have left the optimize_namespace function 'as is'.   Was
  this intentional?  My feeling would be that this is more a part of the
  walker, but maybe this would complicate the callback scheme more than
  it is worth.  This is not critical, though.

2. I would prefer the address of gfc_code ** variant, because it is
   likely we would want to insert, delete or move code.

The patch is OK.  Thanks a lot for your patch!

One remark you might want to consider before following the static
analysis:

In this version, references are not followed.  You would have to
insert code like

  ...
  case EXPR_VARIABLE:
  if ((*e)->ref)
    {
       gfc_array_ref *ar;
       switch ((*e)->ref->type)
         {
            case REF_ARRAY:
               ar=&e->u.ar;
               for (i=0; i<ar->dimen; i++)
                 {
                     if (ar->dimen_type[i] == DIMEN_RANGE)
                        {
			  WALK_SUBEXPR(ar->start[n]);
                          ...
                        }
                     else
                    ... Have to handle integer array indices as well
                 }
         }
    }

to handle array references, similar (but more simple) for substrings, if
you want complete coverage of all expressions.

	Thomas
Jakub Jelinek - Sept. 16, 2010, 5 p.m.
On Wed, Sep 15, 2010 at 11:12:46PM +0200, Thomas Koenig wrote:
> Two remarks:
> 
> 1. I see you have left the optimize_namespace function 'as is'.   Was
>   this intentional?  My feeling would be that this is more a part of the
>   walker, but maybe this would complicate the callback scheme more than
>   it is worth.  This is not critical, though.

I think only time will tell, but in many cases I think you don't want to
walk all the nested namespaces, in some cases only some of them (e.g.
referenced from EXEC_BLOCK), but not contained procedures, etc.

> 2. I would prefer the address of gfc_code ** variant, because it is
>    likely we would want to insert, delete or move code.
> 
> The patch is OK.  Thanks a lot for your patch!

Ok, thanks, committed.

> One remark you might want to consider before following the static
> analysis:

Well, the walker needs to be complete, walk all embedded gfc_exprs,
otherwise e.g. static points to wouldn't work correctly.
So it is not just about wanting or not wanting.

> In this version, references are not followed.  You would have to
> insert code like

Thanks.  Don't other EXPR types have ref, or is it just EXPR_VARIABLE?
If the references have embedded exprs, then those have to be walked.
Will look at it.

If you have other things the walker doesn't walk, please let me know.

	Jakub

Patch

--- gcc/fortran/gfortran.h.jj	2010-09-14 15:24:43.000000000 +0200
+++ gcc/fortran/gfortran.h	2010-09-15 13:02:37.000000000 +0200
@@ -2886,4 +2886,10 @@  gfc_symtree* gfc_get_tbp_symtree (gfc_sy
 
 void gfc_run_passes (gfc_namespace *);
 
+typedef int (*walk_code_fn_t) (gfc_code **, int *, void *);
+typedef int (*walk_expr_fn_t) (gfc_expr **, int *, void *);
+
+int gfc_expr_walker (gfc_expr **, walk_expr_fn_t, void *);
+int gfc_code_walker (gfc_code **, walk_code_fn_t, walk_expr_fn_t, void *);
+
 #endif /* GCC_GFORTRAN_H  */
--- gcc/fortran/frontend-passes.c.jj	2010-09-14 15:24:26.000000000 +0200
+++ gcc/fortran/frontend-passes.c	2010-09-15 18:16:17.000000000 +0200
@@ -30,13 +30,8 @@  along with GCC; see the file COPYING3.  
 static void strip_function_call (gfc_expr *);
 static void optimize_namespace (gfc_namespace *);
 static void optimize_assignment (gfc_code *);
-static void optimize_expr_0 (gfc_expr *);
-static bool optimize_expr (gfc_expr *);
 static bool optimize_op (gfc_expr *);
 static bool optimize_equality (gfc_expr *, bool);
-static void optimize_code (gfc_code *);
-static void optimize_code_node (gfc_code *);
-static void optimize_actual_arglist (gfc_actual_arglist *);
 
 /* Entry point - run all passes for a namespace.  So far, only an
    optimization pass is run.  */
@@ -48,195 +43,39 @@  gfc_run_passes (gfc_namespace *ns)
     optimize_namespace (ns);
 }
 
-/* Optimize a namespace, including all contained namespaces.  */
+/* Callback for each gfc_code node invoked through gfc_code_walker
+   from optimize_namespace.  */
 
-static void
-optimize_namespace (gfc_namespace *ns)
+static int
+optimize_code (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
+	       void *data ATTRIBUTE_UNUSED)
 {
-  optimize_code (ns->code);
-
-  for (ns = ns->contained; ns; ns = ns->sibling)
-    optimize_namespace (ns);
+  if ((*c)->op == EXEC_ASSIGN)
+    optimize_assignment (*c);
+  return 0;
 }
 
-static void
-optimize_code (gfc_code *c)
+/* Callback for each gfc_expr node invoked through gfc_code_walker
+   from optimize_namespace.  */
+
+static int
+optimize_expr (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED,
+	       void *data ATTRIBUTE_UNUSED)
 {
-  for (; c; c = c->next)
-    optimize_code_node (c);
+  if ((*e)->expr_type == EXPR_OP && optimize_op (*e))
+    gfc_simplify_expr (*e, 0);
+  return 0;
 }
 
-
-/* Do the optimizations for a code node.  */
+/* Optimize a namespace, including all contained namespaces.  */
 
 static void
-optimize_code_node (gfc_code *c)
+optimize_namespace (gfc_namespace *ns)
 {
+  gfc_code_walker (&ns->code, optimize_code, optimize_expr, NULL);
 
-  gfc_forall_iterator *fa;
-  gfc_code *d;
-  gfc_alloc *a;
-
-  switch (c->op)
-    {
-    case EXEC_ASSIGN:
-      optimize_assignment (c);
-      break;
-
-    case EXEC_CALL:
-    case EXEC_ASSIGN_CALL:
-    case EXEC_CALL_PPC:
-      optimize_actual_arglist (c->ext.actual);
-      break;
-
-    case EXEC_ARITHMETIC_IF:
-      optimize_expr_0 (c->expr1);
-      break;
-
-    case EXEC_PAUSE:
-    case EXEC_RETURN:
-    case EXEC_ERROR_STOP:
-    case EXEC_STOP:
-    case EXEC_COMPCALL:
-      optimize_expr_0 (c->expr1);
-      break;
-
-    case EXEC_SYNC_ALL:
-    case EXEC_SYNC_MEMORY:
-    case EXEC_SYNC_IMAGES:
-      optimize_expr_0 (c->expr2);
-      break;
-
-    case EXEC_IF:
-      d = c->block;
-      optimize_expr_0 (d->expr1);
-      optimize_code (d->next);
-
-      for (d = d->block; d; d = d->block)
-	{
-	  optimize_expr_0 (d->expr1);
-
-	  optimize_code (d->next);
-	}
-
-
-      break;
-
-    case EXEC_SELECT:
-    case EXEC_SELECT_TYPE:
-      d = c->block;
-
-      optimize_expr_0 (c->expr1);
-
-      for (; d; d = d->block)
-	optimize_code (d->next);
-
-      break;
-
-    case EXEC_WHERE:
-      d = c->block;
-      optimize_expr_0 (d->expr1);
-      optimize_code (d->next);
-
-      for (d = d->block; d; d = d->block)
-	{
-	  optimize_expr_0 (d->expr1);
-	  optimize_code (d->next);
-	}
-      break;
-
-    case EXEC_FORALL:
-
-      for (fa = c->ext.forall_iterator; fa; fa = fa->next)
-	{
-	  optimize_expr_0 (fa->start);
-	  optimize_expr_0 (fa->end);
-	  optimize_expr_0 (fa->stride);
-	}
-
-      if (c->expr1 != NULL)
-	  optimize_expr_0 (c->expr1);
-
-      optimize_code (c->block->next);
-
-      break;
-
-    case EXEC_CRITICAL:
-      optimize_code (c->block->next);
-      break;
-
-    case EXEC_DO:
-      optimize_expr_0 (c->ext.iterator->start);
-      optimize_expr_0 (c->ext.iterator->end);
-      optimize_expr_0 (c->ext.iterator->step);
-      optimize_code (c->block->next);
-
-      break;
-
-    case EXEC_DO_WHILE:
-      optimize_expr_0 (c->expr1);
-      optimize_code (c->block->next);
-      break;
-
-
-    case EXEC_ALLOCATE:
-      for (a = c->ext.alloc.list; a; a = a->next)
-	  optimize_expr_0 (a->expr);
-      break;
-
-      /* Todo:  Some of these may need to be optimized, as well.  */
-    case EXEC_WRITE:
-    case EXEC_READ:
-    case EXEC_OPEN:
-    case EXEC_INQUIRE:
-    case EXEC_REWIND:
-    case EXEC_ENDFILE:
-    case EXEC_BACKSPACE:
-    case EXEC_CLOSE:
-    case EXEC_WAIT:
-    case EXEC_TRANSFER:
-    case EXEC_FLUSH:
-    case EXEC_IOLENGTH:
-    case EXEC_END_PROCEDURE:
-    case EXEC_NOP:
-    case EXEC_CONTINUE:
-    case EXEC_ENTRY:
-    case EXEC_INIT_ASSIGN:
-    case EXEC_LABEL_ASSIGN:
-    case EXEC_POINTER_ASSIGN:
-    case EXEC_GOTO:
-    case EXEC_CYCLE:
-    case EXEC_EXIT:
-    case EXEC_BLOCK:
-    case EXEC_END_BLOCK:
-    case EXEC_OMP_ATOMIC:
-    case EXEC_OMP_BARRIER:
-    case EXEC_OMP_CRITICAL:
-    case EXEC_OMP_FLUSH:
-    case EXEC_OMP_DO:
-    case EXEC_OMP_MASTER:
-    case EXEC_OMP_ORDERED:
-    case EXEC_OMP_PARALLEL:
-    case EXEC_OMP_PARALLEL_DO:
-    case EXEC_OMP_PARALLEL_SECTIONS:
-    case EXEC_OMP_PARALLEL_WORKSHARE:
-    case EXEC_OMP_SECTIONS:
-    case EXEC_OMP_SINGLE:
-    case EXEC_OMP_TASK:
-    case EXEC_OMP_TASKWAIT:
-    case EXEC_OMP_WORKSHARE:
-    case EXEC_OMP_END_NOWAIT:
-    case EXEC_OMP_END_SINGLE:
-    case EXEC_DEALLOCATE:
-    case EXEC_DT_END:
-      for (d = c->block; d; d = d->block)
-	optimize_code (d->next);
-      break;
-
-    default:
-      gcc_unreachable ();
-
-    }
+  for (ns = ns->contained; ns; ns = ns->sibling)
+    optimize_namespace (ns);
 }
 
 /* Replace code like
@@ -336,15 +175,6 @@  optimize_assignment (gfc_code * c)
 
   if (lhs->rank > 0 && gfc_check_dependency (lhs, rhs, true) == 0)
     optimize_binop_array_assignment (c, &rhs, false);
-
-  /* If we insert a statement after the current one, the surrounding loop in
-     optimize_code will call optimize_assignment on the inserted statement
-     anyway, so there is no need to call optimize_assignment again.  */
-
-  /* All direct optimizations have been done.  Now it's time
-     to optimize the rhs.  */
-
-  optimize_expr_0 (rhs);
 }
 
 
@@ -375,58 +205,12 @@  strip_function_call (gfc_expr *e)
 
 }
 
-/* Top-level optimization of expressions.  Calls gfc_simplify_expr if
-   optimize_expr succeeds in doing something.
-   TODO: Optimization of multiple function occurrence to come here.  */
-
-static void
-optimize_expr_0 (gfc_expr * e)
-{
-  if (optimize_expr (e))
-    gfc_simplify_expr (e, 0);
-
-  return;
-}
-
-/* Recursive optimization of expressions.
- TODO:  Make this handle many more things.  */
-
-static bool
-optimize_expr (gfc_expr *e)
-{
-  bool ret;
-
-  if (e == NULL)
-    return false;
-
-  ret = false;
-
-  switch (e->expr_type)
-    {
-    case EXPR_OP:
-      return optimize_op (e);
-      break;
-
-    case EXPR_FUNCTION:
-      optimize_actual_arglist (e->value.function.actual);
-      break;
-
-    default:
-      break;
-    }
-
-  return ret;
-}
-
 /* Recursive optimization of operators.  */
 
 static bool
 optimize_op (gfc_expr *e)
 {
-
-  gfc_intrinsic_op op;
-
-  op = e->value.op.op;
+  gfc_intrinsic_op op = e->value.op.op;
 
   switch (op)
     {
@@ -437,7 +221,6 @@  optimize_op (gfc_expr *e)
     case INTRINSIC_LE:
     case INTRINSIC_LE_OS:
       return optimize_equality (e, true);
-      break;
 
     case INTRINSIC_NE:
     case INTRINSIC_NE_OS:
@@ -446,7 +229,6 @@  optimize_op (gfc_expr *e)
     case INTRINSIC_LT:
     case INTRINSIC_LT_OS:
       return optimize_equality (e, false);
-      break;
 
     default:
       break;
@@ -460,7 +242,6 @@  optimize_op (gfc_expr *e)
 static bool
 optimize_equality (gfc_expr *e, bool equal)
 {
-
   gfc_expr *op1, *op2;
   bool change;
 
@@ -519,18 +300,245 @@  optimize_equality (gfc_expr *e, bool equ
   return false;
 }
 
-/* Optimize a call list.  Right now, this just goes through the actual
-   arg list and optimizes each expression in turn.  */
-
-static void
-optimize_actual_arglist (gfc_actual_arglist *a)
-{
-
-  for (; a; a = a->next)
-    {
-      if (a->expr != NULL)
-	optimize_expr_0 (a->expr);
+#define WALK_SUBEXPR(NODE) \
+  do							\
+    {							\
+      result = gfc_expr_walker (&(NODE), exprfn, data);	\
+      if (result)					\
+	return result;					\
+    }							\
+  while (0)
+#define WALK_SUBEXPR_TAIL(NODE) e = &(NODE); continue
+
+int
+gfc_expr_walker (gfc_expr **e, walk_expr_fn_t exprfn, void *data)
+{
+  while (*e)
+    {
+      int walk_subtrees = 1;
+      gfc_actual_arglist *a;
+      int result = exprfn (e, &walk_subtrees, data);
+      if (result)
+	return result;
+      if (walk_subtrees)
+	switch ((*e)->expr_type)
+	  {
+	  case EXPR_OP:
+	    WALK_SUBEXPR ((*e)->value.op.op1);
+	    WALK_SUBEXPR_TAIL ((*e)->value.op.op2);
+	    break;
+	  case EXPR_FUNCTION:
+	    for (a = (*e)->value.function.actual; a; a = a->next)
+	      WALK_SUBEXPR (a->expr);
+	    break;
+	  case EXPR_COMPCALL:
+	  case EXPR_PPC:
+	    WALK_SUBEXPR ((*e)->value.compcall.base_object);
+	    for (a = (*e)->value.compcall.actual; a; a = a->next)
+	      WALK_SUBEXPR (a->expr);
+	    break;
+	  default:
+	    break;
+	  }
+      return 0;
+    }
+  return 0;
+}
+
+#define WALK_SUBCODE(NODE) \
+  do								\
+    {								\
+      result = gfc_code_walker (&(NODE), codefn, exprfn, data);	\
+      if (result)						\
+	return result;						\
+    }								\
+  while (0)
+
+int
+gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
+		 void *data)
+{
+  for (; *c; c = &(*c)->next)
+    {
+      int walk_subtrees = 1;
+      int result = codefn (c, &walk_subtrees, data);
+      if (result)
+	return result;
+      if (walk_subtrees)
+	{
+	  gfc_code *b;
+	  switch ((*c)->op)
+	    {
+	    case EXEC_DO:
+	      WALK_SUBEXPR ((*c)->ext.iterator->var);
+	      WALK_SUBEXPR ((*c)->ext.iterator->start);
+	      WALK_SUBEXPR ((*c)->ext.iterator->end);
+	      WALK_SUBEXPR ((*c)->ext.iterator->step);
+	      break;
+	    case EXEC_SELECT:
+	      WALK_SUBEXPR ((*c)->expr1);
+	      for (b = (*c)->block; b; b = b->block)
+		{
+		  gfc_case *cp;
+		  for (cp = b->ext.case_list; cp; cp = cp->next)
+		    {
+		      WALK_SUBEXPR (cp->low);
+		      WALK_SUBEXPR (cp->high);
+		    }
+		  WALK_SUBCODE (b->next);
+		}
+	      continue;
+	    case EXEC_ALLOCATE:
+	    case EXEC_DEALLOCATE:
+	      {
+		gfc_alloc *a;
+		for (a = (*c)->ext.alloc.list; a; a = a->next)
+		  WALK_SUBEXPR (a->expr);
+		break;
+	      }
+	    case EXEC_FORALL:
+	      {
+		gfc_forall_iterator *fa;
+		for (fa = (*c)->ext.forall_iterator; fa; fa = fa->next)
+		  {
+		    WALK_SUBEXPR (fa->var);
+		    WALK_SUBEXPR (fa->start);
+		    WALK_SUBEXPR (fa->end);
+		    WALK_SUBEXPR (fa->stride);
+		  }
+		break;
+	      }
+	    case EXEC_OPEN:
+	      WALK_SUBEXPR ((*c)->ext.open->unit);
+	      WALK_SUBEXPR ((*c)->ext.open->file);
+	      WALK_SUBEXPR ((*c)->ext.open->status);
+	      WALK_SUBEXPR ((*c)->ext.open->access);
+	      WALK_SUBEXPR ((*c)->ext.open->form);
+	      WALK_SUBEXPR ((*c)->ext.open->recl);
+	      WALK_SUBEXPR ((*c)->ext.open->blank);
+	      WALK_SUBEXPR ((*c)->ext.open->position);
+	      WALK_SUBEXPR ((*c)->ext.open->action);
+	      WALK_SUBEXPR ((*c)->ext.open->delim);
+	      WALK_SUBEXPR ((*c)->ext.open->pad);
+	      WALK_SUBEXPR ((*c)->ext.open->iostat);
+	      WALK_SUBEXPR ((*c)->ext.open->iomsg);
+	      WALK_SUBEXPR ((*c)->ext.open->convert);
+	      WALK_SUBEXPR ((*c)->ext.open->decimal);
+	      WALK_SUBEXPR ((*c)->ext.open->encoding);
+	      WALK_SUBEXPR ((*c)->ext.open->round);
+	      WALK_SUBEXPR ((*c)->ext.open->sign);
+	      WALK_SUBEXPR ((*c)->ext.open->asynchronous);
+	      WALK_SUBEXPR ((*c)->ext.open->id);
+	      WALK_SUBEXPR ((*c)->ext.open->newunit);
+	      break;
+	    case EXEC_CLOSE:
+	      WALK_SUBEXPR ((*c)->ext.close->unit);
+	      WALK_SUBEXPR ((*c)->ext.close->status);
+	      WALK_SUBEXPR ((*c)->ext.close->iostat);
+	      WALK_SUBEXPR ((*c)->ext.close->iomsg);
+	      break;
+	    case EXEC_BACKSPACE:
+	    case EXEC_ENDFILE:
+	    case EXEC_REWIND:
+	    case EXEC_FLUSH:
+	      WALK_SUBEXPR ((*c)->ext.filepos->unit);
+	      WALK_SUBEXPR ((*c)->ext.filepos->iostat);
+	      WALK_SUBEXPR ((*c)->ext.filepos->iomsg);
+	      break;
+	    case EXEC_INQUIRE:
+	      WALK_SUBEXPR ((*c)->ext.inquire->unit);
+	      WALK_SUBEXPR ((*c)->ext.inquire->file);
+	      WALK_SUBEXPR ((*c)->ext.inquire->iomsg);
+	      WALK_SUBEXPR ((*c)->ext.inquire->iostat);
+	      WALK_SUBEXPR ((*c)->ext.inquire->exist);
+	      WALK_SUBEXPR ((*c)->ext.inquire->opened);
+	      WALK_SUBEXPR ((*c)->ext.inquire->number);
+	      WALK_SUBEXPR ((*c)->ext.inquire->named);
+	      WALK_SUBEXPR ((*c)->ext.inquire->name);
+	      WALK_SUBEXPR ((*c)->ext.inquire->access);
+	      WALK_SUBEXPR ((*c)->ext.inquire->sequential);
+	      WALK_SUBEXPR ((*c)->ext.inquire->direct);
+	      WALK_SUBEXPR ((*c)->ext.inquire->form);
+	      WALK_SUBEXPR ((*c)->ext.inquire->formatted);
+	      WALK_SUBEXPR ((*c)->ext.inquire->unformatted);
+	      WALK_SUBEXPR ((*c)->ext.inquire->recl);
+	      WALK_SUBEXPR ((*c)->ext.inquire->nextrec);
+	      WALK_SUBEXPR ((*c)->ext.inquire->blank);
+	      WALK_SUBEXPR ((*c)->ext.inquire->position);
+	      WALK_SUBEXPR ((*c)->ext.inquire->action);
+	      WALK_SUBEXPR ((*c)->ext.inquire->read);
+	      WALK_SUBEXPR ((*c)->ext.inquire->write);
+	      WALK_SUBEXPR ((*c)->ext.inquire->readwrite);
+	      WALK_SUBEXPR ((*c)->ext.inquire->delim);
+	      WALK_SUBEXPR ((*c)->ext.inquire->encoding);
+	      WALK_SUBEXPR ((*c)->ext.inquire->pad);
+	      WALK_SUBEXPR ((*c)->ext.inquire->iolength);
+	      WALK_SUBEXPR ((*c)->ext.inquire->convert);
+	      WALK_SUBEXPR ((*c)->ext.inquire->strm_pos);
+	      WALK_SUBEXPR ((*c)->ext.inquire->asynchronous);
+	      WALK_SUBEXPR ((*c)->ext.inquire->decimal);
+	      WALK_SUBEXPR ((*c)->ext.inquire->pending);
+	      WALK_SUBEXPR ((*c)->ext.inquire->id);
+	      WALK_SUBEXPR ((*c)->ext.inquire->sign);
+	      WALK_SUBEXPR ((*c)->ext.inquire->size);
+	      WALK_SUBEXPR ((*c)->ext.inquire->round);
+	      break;
+	    case EXEC_WAIT:
+	      WALK_SUBEXPR ((*c)->ext.wait->unit);
+	      WALK_SUBEXPR ((*c)->ext.wait->iostat);
+	      WALK_SUBEXPR ((*c)->ext.wait->iomsg);
+	      WALK_SUBEXPR ((*c)->ext.wait->id);
+	      break;
+	    case EXEC_READ:
+	    case EXEC_WRITE:
+	      WALK_SUBEXPR ((*c)->ext.dt->io_unit);
+	      WALK_SUBEXPR ((*c)->ext.dt->format_expr);
+	      WALK_SUBEXPR ((*c)->ext.dt->rec);
+	      WALK_SUBEXPR ((*c)->ext.dt->advance);
+	      WALK_SUBEXPR ((*c)->ext.dt->iostat);
+	      WALK_SUBEXPR ((*c)->ext.dt->size);
+	      WALK_SUBEXPR ((*c)->ext.dt->iomsg);
+	      WALK_SUBEXPR ((*c)->ext.dt->id);
+	      WALK_SUBEXPR ((*c)->ext.dt->pos);
+	      WALK_SUBEXPR ((*c)->ext.dt->asynchronous);
+	      WALK_SUBEXPR ((*c)->ext.dt->blank);
+	      WALK_SUBEXPR ((*c)->ext.dt->decimal);
+	      WALK_SUBEXPR ((*c)->ext.dt->delim);
+	      WALK_SUBEXPR ((*c)->ext.dt->pad);
+	      WALK_SUBEXPR ((*c)->ext.dt->round);
+	      WALK_SUBEXPR ((*c)->ext.dt->sign);
+	      WALK_SUBEXPR ((*c)->ext.dt->extra_comma);
+	      break;
+	    case EXEC_OMP_DO:
+	    case EXEC_OMP_PARALLEL:
+	    case EXEC_OMP_PARALLEL_DO:
+	    case EXEC_OMP_PARALLEL_SECTIONS:
+	    case EXEC_OMP_PARALLEL_WORKSHARE:
+	    case EXEC_OMP_SECTIONS:
+	    case EXEC_OMP_SINGLE:
+	    case EXEC_OMP_WORKSHARE:
+	    case EXEC_OMP_END_SINGLE:
+	    case EXEC_OMP_TASK:
+	      if ((*c)->ext.omp_clauses)
+		{
+		  WALK_SUBEXPR ((*c)->ext.omp_clauses->if_expr);
+		  WALK_SUBEXPR ((*c)->ext.omp_clauses->num_threads);
+		  WALK_SUBEXPR ((*c)->ext.omp_clauses->chunk_size);
+		}
+	      break;
+	    default:
+	      break;
+	    }
+	  WALK_SUBEXPR ((*c)->expr1);
+	  WALK_SUBEXPR ((*c)->expr2);
+	  WALK_SUBEXPR ((*c)->expr3);
+	  for (b = (*c)->block; b; b = b->block)
+	    {
+	      WALK_SUBEXPR (b->expr1);
+	      WALK_SUBEXPR (b->expr2);
+	      WALK_SUBCODE (b->next);
+	    }
+	}
     }
-  
-  return;
+  return 0;
 }