OSDN Git Service

* gcc.texi: Fixes for makeinfo 4.0 --html.
[pf3gnuchains/gcc-fork.git] / gcc / c-iterate.c
index 4b309d1..1692d2a 100644 (file)
@@ -1,5 +1,6 @@
 /* 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, 1994, 1995, 1996
+   1997, 1998, 2000 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,7 +16,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 /* This file is part of the C front end.
@@ -23,99 +25,136 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    both their declarations and the expansion of statements using them.  */
 
 #include "config.h"
-#include <stdio.h>
+#include "system.h"
 #include "tree.h"
 #include "c-tree.h"
 #include "flags.h"
-
-static void expand_stmt_with_iterators_1 ();
-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 ();
+#include "obstack.h"
+#include "rtl.h"
+#include "toplev.h"
+#include "expr.h"
 \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;
+
+/* 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;
+
+/* During collect_iterators, a list of SAVE_EXPRs already scanned.  */
+static tree save_exprs;
+
+static void expand_stmt_with_iterators_1 PARAMS ((tree, tree));
+static tree collect_iterators          PARAMS ((tree, tree));
+static void iterator_loop_prologue     PARAMS ((tree, rtx *, rtx *));
+static void iterator_loop_epilogue     PARAMS ((tree, rtx *, rtx *));
+static int top_level_ixpansion_p       PARAMS ((void));
+static void isn_append                 PARAMS ((struct iter_stack_node *,
+                                                struct iter_stack_node *));
+static void istack_sublevel_to_current PARAMS ((void));
+static void add_ixpansion              PARAMS ((tree, rtx, rtx, rtx, rtx));
+static void delete_ixpansion           PARAMS ((tree));
+\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 +185,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 +212,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 +227,47 @@ 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;
+             default:
+               break;
+             }
+               
            for (i = 0; i < num_args; i++)
              list = collect_iterators (TREE_OPERAND (exp, i), list);
            return list;
          }
+       default:
+         return list;
        }
     }
 }
@@ -212,18 +285,23 @@ 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,
+              EXPAND_NORMAL);
 
   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, EXPAND_NORMAL);
 
   expand_start_loop_continue_elsewhere (1);
 
@@ -238,17 +316,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,79 +340,25 @@ 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, EXPAND_NORMAL);
   test = build_binary_op (LT_EXPR, idecl, DECL_INITIAL (idecl), 0);
   expand_exit_loop_if_false (0, test);
   expand_end_loop ();
 
   ITERATOR_BOUND_P (idecl) = 0;
   /* we can reset rtl since there is not chance that this expansion */
-  /* would be superceded by a higher level one */
-  if (top_level_ixpansion_p ())
+  /* would be superseded by a higher level one */
+  /* but don't do this if the decl is static, since we need to share */
+  /* the same decl in that case.  */
+  if (top_level_ixpansion_p () && ! TREE_STATIC (idecl))
     DECL_RTL (idecl) = 0;
   if (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 ()
@@ -393,7 +418,7 @@ void
 push_iterator_stack ()
 {
   struct iter_stack_node *new_top
-    = (struct iter_stack_node*) 
+    = (struct iter_stack_node *) 
       obstack_alloc (&ixp_obstack, sizeof (struct iter_stack_node));
 
   new_top->first = 0;
@@ -418,7 +443,7 @@ pop_iterator_stack ()
 \f
 
 /* Record an iterator expansion ("ixpansion") for IDECL.
-   The remaining paramters are the notes in the loop entry
+   The remaining parameters are the notes in the loop entry
    and exit rtl.  */
 
 static void
@@ -426,15 +451,15 @@ add_ixpansion (idecl, pro_start, pro_end, epi_start, epi_end)
      tree idecl;
      rtx pro_start, pro_end, epi_start, epi_end;
 {
-  struct ixpansionnewix;
+  struct ixpansion *newix;
     
   /* Do nothing if we are not inside "({...})",
      as in that case this expansion can't need subsequent RTL modification.  */
   if (iter_stack == 0)
     return;
 
-  newix = (struct ixpansion*) obstack_alloc (&ixp_obstack,
-                                            sizeof (struct ixpansion));
+  newix = (struct ixpansion *) obstack_alloc (&ixp_obstack,
+                                             sizeof (struct ixpansion));
   newix->ixdecl = idecl;
   newix->ixprologue_start = pro_start;
   newix->ixprologue_end   = pro_end;
@@ -455,7 +480,7 @@ static void
 delete_ixpansion (idecl)
      tree idecl;
 {
-  struct ixpansionprevix = 0, *ix;
+  struct ixpansion *previx = 0, *ix;
 
   for (ix = sublevel_ixpansions.first; ix; ix = ix->next)
     if (ix->ixdecl == idecl)
@@ -465,7 +490,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,41 +520,30 @@ 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);
        }
       else
-       fprintf (stderr, "<<Not a Decl!!!>>");
+       fprintf (stderr, "<<?>>");
     }
   else
-    fprintf (stderr, "<<NULL!!>>");
+    fprintf (stderr, "<<0>>");
 }
 
 /* Print Iterator List -- names only */
@@ -539,10 +553,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 +577,7 @@ pixl (head)
   for (current=head; current; current = next)
     {
       tree node = current->ixdecl;
-      PRDECL (node);
+      prdecl (node);
       next = current->next;
       if (next)
        fprintf (stderr, ",");
@@ -572,7 +586,7 @@ pixl (head)
   return head;
 }
 
-/* Print Iterator Stack*/
+/* Print Iterator Stack.  */
 
 void
 pis ()
@@ -587,4 +601,5 @@ pis ()
        stack_node = stack_node->next)
     pixl (stack_node->first);
 }
-#endif
+
+#endif /* DEBUG_ITERATORS */