]> gcc.gnu.org Git - gcc.git/blobdiff - gcc/c-iterate.c
Make more robust in two places.
[gcc.git] / gcc / c-iterate.c
index 4b309d1703afbc97b46829ad14929124dc548bf8..99f9a794d2ae26dfac22c9db7a261ea57bd48217 100644 (file)
@@ -1,5 +1,5 @@
 /* Build expressions with type checking for C compiler.
-   Copyright (C) 1987, 1988, 1989, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1989, 1992, 1993 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -27,95 +27,129 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "tree.h"
 #include "c-tree.h"
 #include "flags.h"
+#include "obstack.h"
+#include "rtl.h"
 
 static void expand_stmt_with_iterators_1 ();
-static tree collect_iterators();
+static tree collect_iterators ();
 static void iterator_loop_prologue ();
 static void iterator_loop_epilogue ();
 static void add_ixpansion ();
 static void delete_ixpansion();
 static int top_level_ixpansion_p ();
 static void istack_sublevel_to_current ();
+
+/* A special obstack, and a pointer to the start of
+   all the data in it (so we can free everything easily).  */
+static struct obstack ixp_obstack;
+static char *ixp_firstobj;
 \f
-void
-iterator_for_loop_start (idecl)
-     tree idecl;
+/*
+               KEEPING TRACK OF EXPANSIONS
+
+   In order to clean out expansions corresponding to statements inside
+   "{(...)}" constructs we have to keep track of all expansions.  The
+   cleanup is needed when an automatic, or implicit, expansion on
+   iterator, say X, happens to a statement which contains a {(...)}
+   form with a statement already expanded on X.  In this case we have
+   to go back and cleanup the inner expansion.  This can be further
+   complicated by the fact that {(...)} can be nested.
+
+   To make this cleanup possible, we keep lists of all expansions, and
+   to make it work for nested constructs, we keep a stack.  The list at
+   the top of the stack (ITER_STACK.CURRENT_LEVEL) corresponds to the
+   currently parsed level.  All expansions of the levels below the
+   current one are kept in one list whose head is pointed to by
+   ITER_STACK.SUBLEVEL_FIRST (SUBLEVEL_LAST is there for making merges
+   easy).  The process works as follows:
+
+   -- On "({"  a new node is added to the stack by PUSH_ITERATOR_STACK.
+              The sublevel list is not changed at this point.
+
+   -- On "})" the list for the current level is appended to the sublevel
+             list. 
+
+   -- On ";"  sublevel lists are appended to the current level lists.
+             The reason is this: if they have not been superseded by the
+             expansion at the current level, they still might be
+             superseded later by the expansion on the higher level.
+             The levels do not have to distinguish levels below, so we
+             can merge the lists together.  */
+
+struct  ixpansion
 {
-  iterator_loop_prologue (idecl, 0, 0);
-}
+  tree ixdecl;                 /* Iterator decl */
+  rtx  ixprologue_start;       /* First insn of epilogue. NULL means */
+  /* explicit (FOR) expansion*/
+  rtx  ixprologue_end;
+  rtx  ixepilogue_start;
+  rtx  ixepilogue_end;
+  struct ixpansion *next;      /* Next in the list */
+};
+
+struct iter_stack_node
+{
+  struct ixpansion *first;     /* Head of list of ixpansions */
+  struct ixpansion *last;      /* Last node in list  of ixpansions */
+  struct iter_stack_node *next; /* Next level iterator stack node  */
+};
+
+struct iter_stack_node *iter_stack;
+
+struct iter_stack_node sublevel_ixpansions;
+
+/* During collect_iterators, a list of SAVE_EXPRs already scanned.  */
+static tree save_exprs;
+\f
+/* Initialize our obstack once per compilation.  */
 
 void
-iterator_for_loop_end (idecl)
-     tree idecl;
+init_iterators ()
 {
-  iterator_loop_epilogue (idecl, 0, 0);
+  gcc_obstack_init (&ixp_obstack);
+  ixp_firstobj = (char *) obstack_alloc (&ixp_obstack, 0);
 }
 
+/* Handle the start of an explicit `for' loop for iterator IDECL.  */
+
 void
-iterator_for_loop_record (idecl)
+iterator_for_loop_start (idecl)
      tree idecl;
 {
+  ITERATOR_BOUND_P (idecl) = 1;
   add_ixpansion (idecl, 0, 0, 0, 0);
+  iterator_loop_prologue (idecl, 0, 0);
 }
 
+/* Handle the end of an explicit `for' loop for iterator IDECL.  */
 
-/*
-               ITERATOR DECLS
-
-Iterators are  implemented  as integer decls  with a special  flag set
-(rms's   idea).  This  makes  eliminates  the need   for  special type
-checking.  The  flag  is accesed using   the  ITERATOR_P  macro.  Each
-iterator's limit is saved as a  decl with a special  name. The decl is
-initialized with the limit value -- this way we  get all the necessary
-semantical processing for free by calling finish  decl. We might still
-eliminate  that decl  later  -- it takes up  time and  space and, more
-importantly, produces strange error  messages when  something is wrong
-with the initializing expresison.  */
-
-tree
-build_iterator_decl (id, limit)
-    tree id, limit;
+void
+iterator_for_loop_end (idecl)
+     tree idecl;
 {
-  tree type = integer_type_node, lim_decl;
-  tree t1, t2, t3;
-  tree start_node, limit_node, step_node;
-  tree decl;
-    
-  if (limit)
-    {
-      limit_node = save_expr (limit);
-      SAVE_EXPR_CONTEXT (limit_node) = current_function_decl;
-    }
-  else
-    abort ();
-  lim_decl = build_limit_decl (id, limit_node);
-  push_obstacks_nochange ();
-  decl = build_decl (VAR_DECL, id, type);
-  ITERATOR_P (decl) = 1;
-  ITERATOR_LIMIT (decl) = lim_decl;
-  finish_decl (pushdecl (decl), 0, 0);
-  return decl;
+  iterator_loop_epilogue (idecl, 0, 0);
+  ITERATOR_BOUND_P (idecl) = 0;
 }
 \f
 /*
                ITERATOR RTL EXPANSIONS
 
-   Expanding simple statements with iterators is  pretty straightforward:
-   collect (collect_iterators) the list  of  all "free" iterators  in the
-   statement and for each  of them add  a  special prologue before and an
-   epilogue after the expansion for  the statement. Iterator is "free" if
-   it has not been "bound" by a FOR operator. The rtx associated with the
-   iterator's  decl is used as  the loop counter.  Special processing  is
-   used  for "{(...)}" constructs:  each iterator expansion is registered
-   (by "add_ixpansion" function)  and inner expansions are superseded  by
-   outer ones. The cleanup of superseded expansions is done by  a call to
-   delete_ixpansion.  */
+   Expanding simple statements with iterators is straightforward:
+   collect the list of all free iterators in the statement, and
+   generate a loop for each of them.
+
+   An iterator is "free" if it has not been "bound" by a FOR
+   operator.  The DECL_RTL of the iterator is the loop counter.  */
+
+/* Expand a statement STMT, possibly containing iterator usage, into RTL.  */
 
 void
 iterator_expand (stmt)
     tree stmt;
 {
-  tree iter_list = collect_iterators (stmt, NULL_TREE);
+  tree iter_list;
+  save_exprs = NULL_TREE;
+  iter_list = collect_iterators (stmt, NULL_TREE);
   expand_stmt_with_iterators_1 (stmt, iter_list);
   istack_sublevel_to_current ();
 }
@@ -146,9 +180,9 @@ expand_stmt_with_iterators_1 (stmt, iter_list)
 }
 
 
-/* Return a list containing all the free (i.e. not bound by "for"
-   statement or anaccumulator) iterators mentioned in EXP,
-   plus those in LIST.   Duplicates are avoided.  */
+/* Return a list containing all the free (i.e. not bound by a
+   containing `for' statement) iterators mentioned in EXP, plus those
+   in LIST.  Do not add duplicate entries to the list.  */
 
 static tree
 collect_iterators (exp, list)
@@ -173,6 +207,14 @@ collect_iterators (exp, list)
        return list;
       }
 
+    case SAVE_EXPR:
+      /* In each scan, scan a given save_expr only once.  */
+      if (value_member (exp, save_exprs))
+       return list;
+
+      save_exprs = tree_cons (NULL_TREE, exp, save_exprs);
+      return collect_iterators (TREE_OPERAND (exp, 0), list);
+
       /* we do not automatically iterate blocks -- one must */
       /* use the FOR construct to do that */
 
@@ -180,21 +222,45 @@ collect_iterators (exp, list)
       return list;
 
     default:
-      switch (TREE_CODE_CLASS (code))
+      switch (TREE_CODE_CLASS (TREE_CODE (exp)))
        {
        case '1':
+         return collect_iterators (TREE_OPERAND (exp, 0), list);
+
        case '2':
        case '<':
+         return collect_iterators (TREE_OPERAND (exp, 0),
+                                   collect_iterators (TREE_OPERAND (exp, 1),
+                                                      list));
+
        case 'e':
        case 'r':
          {
-           int num_args = tree_code_length[code];
+           int num_args = tree_code_length[(int) TREE_CODE (exp)];
            int i;
-           the_list = (tree) 0;
+
+           /* Some tree codes have RTL, not trees, as operands.  */
+           switch (TREE_CODE (exp))
+             {
+             case CALL_EXPR:
+               num_args = 2;
+               break;
+             case METHOD_CALL_EXPR:
+               num_args = 3;
+               break;
+             case WITH_CLEANUP_EXPR:
+               num_args = 1;
+               break;
+             case RTL_EXPR:
+               return list;
+             }
+               
            for (i = 0; i < num_args; i++)
              list = collect_iterators (TREE_OPERAND (exp, i), list);
            return list;
          }
+       default:
+         return list;
        }
     }
 }
@@ -212,18 +278,22 @@ iterator_loop_prologue (idecl, start_note, end_note)
      tree idecl;
      rtx *start_note, *end_note;
 {
+  tree expr;
+
   /* Force the save_expr in DECL_INITIAL to be calculated
      if it hasn't been calculated yet.  */
-  expand_expr (DECL_INITIAL (idecl), 0, VOIDmode, 0);
+  expand_expr (DECL_INITIAL (idecl), const0_rtx, VOIDmode, 0);
 
   if (DECL_RTL (idecl) == 0)
     expand_decl (idecl);
 
   if (start_note)
     *start_note = emit_note (0, NOTE_INSN_DELETED);
+
   /* Initialize counter.  */
-  expand_expr (build_modify_expr (idecl, NOP_EXPR, integer_zero_node),
-              0, VOIDmode, 0);
+  expr = build (MODIFY_EXPR, TREE_TYPE (idecl), idecl, integer_zero_node);
+  TREE_SIDE_EFFECTS (expr) = 1;
+  expand_expr (expr, const0_rtx, VOIDmode, 0);
 
   expand_start_loop_continue_elsewhere (1);
 
@@ -238,17 +308,18 @@ iterator_loop_prologue (idecl, start_note, end_note)
    DECL_RTL is zeroed unless we are inside "({...})". The reason for that is
    described below.
 
-   When we create two (or more)  loops based on the  same IDECL, and both
-   inside the same "({...})"  construct, we  must be prepared  to  delete
-   both of the loops  and create a single one  on the  level  above, i.e.
-   enclosing the "({...})". The new loop has to use  the same counter rtl
-   because the references to the iterator decl  (IDECL) have already been
-   expanded as references to the counter rtl.
+   When we create two (or more) loops based on the same IDECL, and
+   both inside the same "({...})"  construct, we must be prepared to
+   delete both of the loops and create a single one on the level
+   above, i.e.  enclosing the "({...})". The new loop has to use the
+   same counter rtl because the references to the iterator decl
+   (IDECL) have already been expanded as references to the counter
+   rtl.
 
    It is incorrect to use the same counter reg in different functions,
    and it is desirable to use different counters in disjoint loops
-   when we know there's no need to combine them
-   (because then they can get allocated separately).  */
+   when we know there's no need to combine them (because then they can
+   get allocated separately).  */
 
 static void
 iterator_loop_epilogue (idecl, start_note, end_note)
@@ -261,7 +332,9 @@ iterator_loop_epilogue (idecl, start_note, end_note)
     *start_note = emit_note (0, NOTE_INSN_DELETED);
   expand_loop_continue_here ();
   incr = build_binary_op (PLUS_EXPR, idecl, integer_one_node, 0);
-  expand_expr (build_modify_expr (idecl, NOP_EXPR, incr));
+  incr = build (MODIFY_EXPR, TREE_TYPE (idecl), idecl, incr);
+  TREE_SIDE_EFFECTS (incr) = 1;
+  expand_expr (incr, const0_rtx, VOIDmode, 0);
   test = build_binary_op (LT_EXPR, idecl, DECL_INITIAL (idecl), 0);
   expand_exit_loop_if_false (0, test);
   expand_end_loop ();
@@ -275,65 +348,7 @@ iterator_loop_epilogue (idecl, start_note, end_note)
     *end_note = emit_note (0, NOTE_INSN_DELETED);
 }
 \f
-/*
-               KEEPING TRACK OF EXPANSIONS
-
-   In order to clean out expansions corresponding to statements inside
-   "{(...)}" constructs we have to keep track of all expansions.  The
-   cleanup is needed when an automatic, or implicit, expansion on
-   iterator, say X, happens to a statement which contains a {(...)}
-   form with a statement already expanded on X.  In this case we have
-   to go back and cleanup the inner expansion.  This can be further
-   complicated by the fact that {(...)} can be nested.
-
-   To make this cleanup possible, we keep lists of all expansions, and
-   to make it work for nested constructs, we keep a stack.  The list at
-   the top of the stack (ITER_STACK.CURRENT_LEVEL) corresponds to the
-   currently parsed level.  All expansions of the levels below the
-   current one are kept in one list whose head is pointed to by
-   ITER_STACK.SUBLEVEL_FIRST (SUBLEVEL_LAST is there for making merges
-   easy).  The process works as follows:
-
-   -- On "({"  a new node is added to the stack by PUSH_ITERATOR_STACK.
-              The sublevel list is not changed at this point.
-
-   -- On "})" the list for the current level is appended to the sublevel
-             list. 
-
-   -- On ";"  sublevel lists are appended to the current level lists.
-             The reason is this: if they have not been superseded by the
-             expansion at the current level, they still might be
-             superseded later by the expansion on the higher level.
-             The levels do not have to distinguish levels below, so we
-             can merge the lists together.  */
-
-struct  ixpansion
-{
-  tree ixdecl;                 /* Iterator decl */
-  rtx  ixprologue_start;       /* First insn of epilogue. NULL means */
-  /* explicit (FOR) expansion*/
-  rtx  ixprologue_end;
-  rtx  ixepilogue_start;
-  rtx  ixepilogue_end;
-  struct ixpansion *next;      /* Next in the list */
-};
-
-static struct obstack ixp_obstack;
-
-static char *ixp_firstobj;
-
-struct iter_stack_node
-{
-  struct ixpansion *first;     /* Head of list of ixpansions */
-  struct ixpansion *last;      /* Last node in list  of ixpansions */
-  struct iter_stack_node *next; /* Next level iterator stack node  */
-};
-
-struct iter_stack_node *iter_stack;
-
-struct iter_stack_node sublevel_ixpansions;
-
-/** Return true if we are not currently inside a "({...})" construct */
+/* Return true if we are not currently inside a "({...})" construct.  */
 
 static int
 top_level_ixpansion_p ()
@@ -465,7 +480,7 @@ delete_ixpansion (idecl)
 
        if (ix->ixprologue_start == 0)
          error_with_decl (idecl,
-                          "`for (%s)' appears within implicit iteration")
+                          "`for (%s)' appears within implicit iteration");
        else
          {
            rtx insn;
@@ -495,33 +510,22 @@ delete_ixpansion (idecl)
       previx = ix;
 }
 \f
-/*
-We initialize iterators obstack once per file
-*/
-
-init_iterators ()
-{
-  gcc_obstack_init (&ixp_obstack);
-  ixp_firstobj = (char *) obstack_alloc (&ixp_obstack, 0);
-}
-
 #ifdef DEBUG_ITERATORS
 
-/*
-The functions below are for use from source level debugger.
-They print short forms of iterator lists and the iterator stack.
-*/
+/* The functions below are for use from source level debugger.
+   They print short forms of iterator lists and the iterator stack.  */
+
+/* Print the name of the iterator D.  */
 
-/* Print the name of the iterator D */
 void
-PRDECL (D)
-     tree D;
+prdecl (d)
+     tree d;
 {
-  if (D)
+  if (d)
     {
-      if (TREE_CODE (D) == VAR_DECL)
+      if (TREE_CODE (d) == VAR_DECL)
        {
-         tree tname = DECL_NAME (D);
+         tree tname = DECL_NAME (d);
          char *dname = IDENTIFIER_POINTER (tname);
          fprintf (stderr, dname);
        }
@@ -539,10 +543,10 @@ pil (head)
      tree head;
 {
   tree current, next;
-  for (current=head; current; current = next)
+  for (current = head; current; current = next)
     {
       tree node = TREE_VALUE (current);
-      PRDECL (node);
+      prdecl (node);
       next = TREE_CHAIN (current);
       if (next) fprintf (stderr, ",");
     }
@@ -563,7 +567,7 @@ pixl (head)
   for (current=head; current; current = next)
     {
       tree node = current->ixdecl;
-      PRDECL (node);
+      prdecl (node);
       next = current->next;
       if (next)
        fprintf (stderr, ",");
@@ -587,4 +591,5 @@ pis ()
        stack_node = stack_node->next)
     pixl (stack_node->first);
 }
-#endif
+
+#endif /* DEBUG_ITERATORS */
This page took 0.043203 seconds and 5 git commands to generate.