Makefile.in (GGC, GGC_LIB): New.
authorRichard Henderson <rth@cygnus.com>
Sat, 4 Sep 1999 18:25:41 +0000 (11:25 -0700)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Sat, 4 Sep 1999 18:25:41 +0000 (18:25 +0000)
* Makefile.in (GGC, GGC_LIB): New.
(HOST_RTL): Include ggc-none.o.
(ggc-simple.o): New target.
(ggc-none.o): Likewise.
* tree.h (tree_common): Add gc_mark.
* rtl.h (struct rtx_def): Steal a bit from code to make gc_mark.
(struct rtvec_def): Add gc_mark.
* emit-rtl.c (global_rtl): Update static initializers to contain
enough initializers.
* ggc.h, ggc-none.c, ggc-simple.c: New files.
* toplev.c (gc_time): New variable.
(all_time): New variable.
(compile_file): Print gc time.
(print_time): Calculate percentage of the whole.

From-SVN: r29106

gcc/ChangeLog
gcc/Makefile.in
gcc/emit-rtl.c
gcc/ggc-none.c [new file with mode: 0644]
gcc/ggc-simple.c [new file with mode: 0644]
gcc/ggc.h [new file with mode: 0644]
gcc/rtl.h
gcc/toplev.c
gcc/tree.h

index 4e78651c4c567afd713a9ac59189956c6671f9f5..ed79892a25c76b3fe3e512f04e00690d498590cb 100644 (file)
@@ -1,3 +1,20 @@
+Sat Sep  4 11:19:52 1999  Richard Henderson  <rth@cygnus.com>
+
+       * Makefile.in (GGC, GGC_LIB): New.
+       (HOST_RTL): Include ggc-none.o.
+       (ggc-simple.o): New target.
+       (ggc-none.o): Likewise.
+       * tree.h (tree_common): Add gc_mark.
+       * rtl.h (struct rtx_def): Steal a bit from code to make gc_mark.
+       (struct rtvec_def): Add gc_mark.
+       * emit-rtl.c (global_rtl): Update static initializers to contain
+       enough initializers.
+       * ggc.h, ggc-none.c, ggc-simple.c: New files.
+       * toplev.c (gc_time): New variable.
+       (all_time): New variable.
+       (compile_file): Print gc time.
+       (print_time): Calculate percentage of the whole.
+       
 Sat Sep  4 13:11:01 1999  Bernd Schmidt  <bernds@cygnus.co.uk>
 
        Change obstack memory management and varasm constant pool handling so
index 164d939368d49e83c7a5151f0d0e410aaddde83d..333da82d4950a746afa37c9c59967e6f36f6d125 100644 (file)
@@ -316,6 +316,12 @@ CLIB=
 # system library.
 OBSTACK=obstack.o
 
+# The GC method to be used on this system.
+GGC=ggc-simple.o
+
+# If a supplementary library is being used for the GC.
+GGC_LIB=
+
 # Configure will set these if you need vfprintf and possibly _doprnt support.
 VFPRINTF=@vfprintf@
 DOPRINT=@doprint@
@@ -572,7 +578,7 @@ HOST_LIBS = $(USE_HOST_OBSTACK) $(USE_HOST_ALLOCA) $(USE_HOST_MALLOC)  \
            $(HOST_INTLLIBS) $(USE_HOST_VFPRINTF) $(USE_HOST_DOPRINT) \
            $(HOST_CLIB)
 
-HOST_RTL = $(HOST_PREFIX)rtl.o $(HOST_PREFIX)bitmap.o
+HOST_RTL = $(HOST_PREFIX)rtl.o $(HOST_PREFIX)bitmap.o $(HOST_PREFIX)ggc-none.o
 HOST_RTLANAL = $(HOST_PREFIX)rtlanal.o
 HOST_PRINT = $(HOST_PREFIX)print-rtl.o
 HOST_ERRORS = $(HOST_PREFIX)errors.o
@@ -1424,6 +1430,11 @@ gencheck.o : gencheck.c tree.def $(CONFIG_H) hconfig.h system.h
 dumpvers: dumpvers.c
 
 version.o: version.c
+
+ggc-simple.o: ggc-simple.c $(CONFIG_H) $(RTL_BASE_H) $(TREE_H) flags.h ggc.h
+
+ggc-none.o: ggc-none.c $(CONFIG_H) $(RTL_BASE_H) ggc.h
+
 obstack.o: $(srcdir)/../libiberty/obstack.c $(CONFIG_H)
        rm -f obstack.c
        $(LN_S) $(srcdir)/../libiberty/obstack.c obstack.c
index 8d3f2fae61d57f85236e16577b3d10487cc9f782..c16ffe4da404add60824b01c1acaa38058a41f8b 100644 (file)
@@ -93,17 +93,17 @@ static int no_line_numbers;
 
 struct _global_rtl global_rtl =
 {
-  {PC, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0 FLDI },  /* pc_rtx */
-  {CC0, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* cc0_rtx */
-  {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* stack_pointer_rtx */
-  {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* frame_pointer_rtx */
-  {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* hard_frame_pointer_rtx */
-  {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* arg_pointer_rtx */
-  {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* virtual_incoming_args_rtx */
-  {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* virtual_stack_vars_rtx */
-  {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* virtual_stack_dynamic_rtx */
-  {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* virtual_outgoing_args_rtx */
-  {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* virtual_cfa_rtx */
+  {PC, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0, 0 FLDI },  /* pc_rtx */
+  {CC0, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* cc0_rtx */
+  {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* stack_pointer_rtx */
+  {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* frame_pointer_rtx */
+  {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* hard_frame_pointer_rtx */
+  {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* arg_pointer_rtx */
+  {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* virtual_incoming_args_rtx */
+  {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* virtual_stack_vars_rtx */
+  {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* virtual_stack_dynamic_rtx */
+  {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* virtual_outgoing_args_rtx */
+  {REG, VOIDmode, 0, 0, 0, 0, 0, 0, 0, 0, 0 FLDI }, /* virtual_cfa_rtx */
 };
 
 /* We record floating-point CONST_DOUBLEs in each floating-point mode for
diff --git a/gcc/ggc-none.c b/gcc/ggc-none.c
new file mode 100644 (file)
index 0000000..5fff104
--- /dev/null
@@ -0,0 +1,58 @@
+/* Null garbage collection for the GNU compiler.
+   Copyright (C) 1998 Free Software Foundation, Inc.
+
+   This file is part of GNU CC.
+
+   GNU CC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   GNU CC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* This version is used by the gen* programs, where we don't really
+   need GC at all.  This prevents problems with pulling in all the
+   tree stuff.  */
+
+/* We are used by gengenrtl, before genrtl.h exists.  But we don't 
+   need it either.  */
+#define NO_GENRTL_H
+
+#include "config.h"
+#include "system.h"
+#include "rtl.h"
+#include "ggc.h"
+
+rtx
+ggc_alloc_rtx (nslots)
+     int nslots;
+{
+  int size = sizeof(struct rtx_def) + (nslots - 1) * sizeof(rtunion);
+  rtx n;
+
+  n = (rtx) xmalloc (size);
+  bzero ((char *) n, size);
+
+  return n;
+}
+
+rtvec
+ggc_alloc_rtvec (nelt)
+     int nelt;
+{
+  int size = sizeof (struct rtvec_def) + (nelt - 1) * sizeof (rtunion);
+  rtvec v;
+
+  v = (rtvec) xmalloc (size);
+  bzero ((char *) v, size);
+
+  return v;
+}
diff --git a/gcc/ggc-simple.c b/gcc/ggc-simple.c
new file mode 100644 (file)
index 0000000..3ce7bcb
--- /dev/null
@@ -0,0 +1,714 @@
+/* Simple garbage collection for the GNU compiler.
+   Copyright (C) 1998 Free Software Foundation, Inc.
+
+   This file is part of GNU CC.
+
+   GNU CC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   GNU CC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "config.h"
+#include "system.h"
+#include "rtl.h"
+#include "tree.h"
+#include "ggc.h"
+#include "flags.h"
+
+/* Debugging flags.  */
+#undef GGC_DUMP
+#define GGC_POISON
+
+/* Global lists of roots, rtxs, and trees.  */
+
+struct ggc_root
+{
+  struct ggc_root *next;
+  void *base;
+  int nelt;
+  int size;
+  void (*cb)(void *);
+};
+
+static struct ggc_root *roots;
+
+struct ggc_rtx
+{
+  struct ggc_rtx *chain;
+  struct rtx_def rtx;
+};
+
+static struct ggc_rtx *rtxs;
+
+struct ggc_rtvec
+{
+  struct ggc_rtvec *chain;
+  struct rtvec_def vec;
+};
+
+static struct ggc_rtvec *vecs;
+
+struct ggc_tree
+{
+  struct ggc_tree *chain;
+  union tree_node tree;
+};
+
+static struct ggc_tree *trees;
+
+struct ggc_string
+{
+  struct ggc_string *chain;
+  int magic_mark;
+  char string[1];
+};
+
+#define GGC_STRING_MAGIC       ((unsigned int)0xa1b2c3d4)
+
+static struct ggc_string *strings;
+
+/* Some statistics.  */
+
+static int n_rtxs_collected;
+static int n_vecs_collected;
+static int n_trees_collected;
+static int n_strings_collected;
+static int bytes_alloced_since_gc;
+extern int gc_time;
+
+#ifdef GGC_DUMP
+static FILE *dump;
+#endif
+
+/* Local function prototypes.  */
+
+static void ggc_free_rtx PROTO ((struct ggc_rtx *r));
+static void ggc_free_tree PROTO ((struct ggc_tree *t));
+static void ggc_mark_rtx_ptr PROTO ((void *elt));
+static void ggc_mark_tree_ptr PROTO ((void *elt));
+
+/* These allocators are dreadfully simple, with no caching whatsoever so
+   that Purify-like tools that do allocation versioning can catch errors.
+   This collector is never going to go fast anyway.  */
+
+rtx
+ggc_alloc_rtx (nslots)
+     int nslots;
+{
+  struct ggc_rtx *n;
+  int size = sizeof(*n) + (nslots-1) * sizeof(rtunion);
+
+  n = (struct ggc_rtx *) xmalloc (size);
+  bzero ((char *) n, size);
+  n->chain = rtxs;
+  rtxs = n;
+
+#ifdef GGC_DUMP
+  fprintf (dump, "alloc rtx %p\n", &n->rtx);
+#endif
+
+  bytes_alloced_since_gc += size;
+
+  return &n->rtx;
+}
+
+rtvec
+ggc_alloc_rtvec (nelt)
+     int nelt;
+{
+  struct ggc_rtvec *v;
+  int size = sizeof (*v) + (nelt - 1) * sizeof (rtunion);
+
+  v = (struct ggc_rtvec *) xmalloc (size);
+  bzero ((char *) v, size);
+  v->chain = vecs;
+  vecs = v;
+
+#ifdef GGC_DUMP
+  fprintf(dump, "alloc vec %p\n", &v->vec);
+#endif
+
+  bytes_alloced_since_gc += size;
+
+  return &v->vec;
+}
+
+tree
+ggc_alloc_tree (length)
+     int length;
+{
+  struct ggc_tree *n;
+  int size = sizeof(*n) - sizeof(n->tree) + length;
+
+  n = (struct ggc_tree *) xmalloc (size);
+  bzero ((char *) n, size);
+  n->chain = trees;
+  trees = n;
+
+#ifdef GGC_DUMP
+  fprintf(dump, "alloc tree %p\n", &n->tree);
+#endif
+
+  bytes_alloced_since_gc += size;
+
+  return &n->tree;
+}
+
+char *
+ggc_alloc_string (contents, length)
+     const char *contents;
+     int length;
+{
+  struct ggc_string *s;
+  int size;
+
+  if (length < 0)
+    {
+      if (contents == NULL)
+       return NULL;
+      length = strlen (contents);
+    }
+
+  size = (s->string - (char *)s) + length + 1;
+  s = (struct ggc_string *) xmalloc(size);
+  s->chain = strings;
+  s->magic_mark = GGC_STRING_MAGIC;
+  if (contents)
+    bcopy (contents, s->string, length);
+  s->string[length] = 0;
+  strings = s;
+
+#ifdef GGC_DUMP
+  fprintf(dump, "alloc string %p\n", &n->tree);
+#endif
+
+  bytes_alloced_since_gc += size;
+
+  return s->string;
+}
+
+
+/* Freeing a bit of rtl isn't quite as simple as calling free, there are
+   a few associated bits that might need freeing as well.  */
+
+static void
+ggc_free_rtx (r)
+     struct ggc_rtx *r;
+{
+#ifdef GGC_DUMP
+  fprintf (dump, "collect rtx %p\n", &r->rtx);
+#endif
+#ifdef GGC_POISON
+  memset (r, 0xAA, sizeof(*r));
+#endif
+
+  free (r);
+}
+
+/* Freeing an rtvec is as simple as calling free.  */
+
+static void
+ggc_free_rtvec (v)
+     struct ggc_rtvec *v;
+{
+#ifdef GGC_DUMP
+  fprintf(dump, "collect vec %p\n", &v->vec);
+#endif
+#ifdef GGC_POISON
+  memset (v, 0xBB, sizeof (*v) + ((GET_NUM_ELEM (&v->vec) - 1)
+                                 * sizeof (rtunion)));
+#endif
+
+  free (v);
+}
+
+/* Freeing a tree node is almost, but not quite, as simple as calling free.
+   Mostly we need to let the language clean up its lang_specific bits.  */
+
+static void
+ggc_free_tree (t)
+     struct ggc_tree *t;
+{
+  switch (TREE_CODE_CLASS (TREE_CODE (&t->tree)))
+    {
+    case 'd': /* A decl node.  */
+    case 't': /* A type node.  */
+      lang_cleanup_tree (&t->tree);
+      break;
+    }
+
+#ifdef GGC_DUMP
+  fprintf (dump, "collect tree %p\n", &t->tree);
+#endif
+#ifdef GGC_POISON
+  memset(&t->tree.common, 0xCC, sizeof(t->tree.common));
+#endif
+
+  free (t);
+}
+
+/* Freeing a string is as simple as calling free.  */
+
+static void
+ggc_free_string (s)
+     struct ggc_string *s;
+{
+#ifdef GGC_DUMP
+  fprintf(dump, "collect string %p\n", s->string);
+#endif
+#ifdef GGC_POISON
+  s->magic_mark = 0xDDDDDDDD;
+  s->string[0] = 0xDD;
+#endif
+
+  free (s);
+}
+
+/* Mark a node.  */
+
+void
+ggc_mark_rtx (r)
+     rtx r;
+{
+  const char *fmt;
+  int i;
+
+  if (r == NULL_RTX || r->gc_mark)
+    return;
+  r->gc_mark = 1;
+
+  /* ??? If (some of) these are really pass-dependant info, do we have
+     any right poking our noses in?  */
+  switch (GET_CODE (r))
+    {
+    case JUMP_INSN:
+      ggc_mark_rtx (JUMP_LABEL (r));
+      break;
+    case CODE_LABEL:
+      ggc_mark_rtx (LABEL_REFS (r));
+      break;
+    case LABEL_REF:
+      ggc_mark_rtx (LABEL_NEXTREF (r));
+      ggc_mark_rtx (CONTAINING_INSN (r));
+      break;
+    case ADDRESSOF:
+      ggc_mark_tree (ADDRESSOF_DECL (r));
+      break;
+    case CONST_DOUBLE:
+      ggc_mark_rtx (CONST_DOUBLE_CHAIN (r));
+      break;
+
+    default:
+      break;
+    }
+
+  for (fmt = GET_RTX_FORMAT (GET_CODE (r)), i = 0; *fmt ; ++fmt, ++i)
+    {
+      switch (*fmt)
+       {
+       case 'e': case 'u':
+         ggc_mark_rtx (XEXP (r, i));
+         break;
+       case 'V': case 'E':
+         ggc_mark_rtvec (XVEC (r, i));
+         break;
+       case 'S': case 's':
+         ggc_mark_string (XSTR (r, i));
+         break;
+       }
+    }
+}
+
+void
+ggc_mark_rtvec (v)
+     rtvec v;
+{
+  int i;
+
+  if (v == NULL || v->gc_mark)
+    return;
+  v->gc_mark = 1;
+
+  i = GET_NUM_ELEM (v);
+  while (--i >= 0)
+    ggc_mark_rtx (RTVEC_ELT (v, i));
+}
+
+void
+ggc_mark_tree (t)
+     tree t;
+{
+  if (t == NULL_TREE || t->common.gc_mark)
+    return;
+  t->common.gc_mark = 1;
+
+  /* Bits from common.  */
+  ggc_mark_tree (TREE_TYPE (t));
+  ggc_mark_tree (TREE_CHAIN (t));
+
+  /* Some nodes require special handling.  */
+  switch (TREE_CODE (t))
+    {
+    case TREE_LIST:
+      ggc_mark_tree (TREE_PURPOSE (t));
+      ggc_mark_tree (TREE_VALUE (t));
+      return;
+
+    case TREE_VEC:
+      {
+       int i = TREE_VEC_LENGTH (t);
+       while (--i >= 0)
+         ggc_mark_tree (TREE_VEC_ELT (t, i));
+       return;
+      }
+
+    case SAVE_EXPR:
+      ggc_mark_tree (TREE_OPERAND (t, 0));
+      ggc_mark_tree (SAVE_EXPR_CONTEXT (t));
+      ggc_mark_rtx (SAVE_EXPR_RTL (t));
+      return;
+
+    case RTL_EXPR:
+      ggc_mark_rtx (RTL_EXPR_SEQUENCE (t));
+      ggc_mark_rtx (RTL_EXPR_RTL (t));
+      return;
+
+    case CALL_EXPR:
+      ggc_mark_tree (TREE_OPERAND (t, 0));
+      ggc_mark_tree (TREE_OPERAND (t, 1));
+      ggc_mark_rtx (CALL_EXPR_RTL (t));
+      return;
+
+    case COMPLEX_CST:
+      ggc_mark_tree (TREE_REALPART (t));
+      ggc_mark_tree (TREE_IMAGPART (t));
+      break;
+
+    case STRING_CST:
+      ggc_mark_string (TREE_STRING_POINTER (t));
+      break;
+
+    case PARM_DECL:
+      ggc_mark_rtx (DECL_INCOMING_RTL (t));
+      break;
+
+    case IDENTIFIER_NODE:
+      ggc_mark_string (IDENTIFIER_POINTER (t));
+      lang_mark_tree (t);
+      return;
+
+    default:
+      break;
+    }
+  
+  /* But in general we can handle them by class.  */
+  switch (TREE_CODE_CLASS (TREE_CODE (t)))
+    {
+    case 'd': /* A decl node.  */
+      ggc_mark_tree (DECL_SIZE (t));
+      ggc_mark_tree (DECL_NAME (t));
+      ggc_mark_tree (DECL_CONTEXT (t));
+      ggc_mark_tree (DECL_ARGUMENTS (t));
+      ggc_mark_tree (DECL_RESULT (t));
+      ggc_mark_tree (DECL_INITIAL (t));
+      ggc_mark_tree (DECL_ABSTRACT_ORIGIN (t));
+      ggc_mark_tree (DECL_ASSEMBLER_NAME (t));
+      ggc_mark_tree (DECL_SECTION_NAME (t));
+      ggc_mark_tree (DECL_MACHINE_ATTRIBUTES (t));
+      ggc_mark_rtx (DECL_RTL (t));
+      ggc_mark_tree (DECL_VINDEX (t));
+      lang_mark_tree (t);
+      break;
+
+    case 't': /* A type node.  */
+      ggc_mark_tree (TYPE_SIZE (t));
+      ggc_mark_tree (TYPE_SIZE_UNIT (t));
+      ggc_mark_tree (TYPE_ATTRIBUTES (t));
+      ggc_mark_tree (TYPE_VALUES (t));
+      ggc_mark_tree (TYPE_POINTER_TO (t));
+      ggc_mark_tree (TYPE_REFERENCE_TO (t));
+      ggc_mark_tree (TYPE_NAME (t));
+      ggc_mark_tree (TYPE_MIN_VALUE (t));
+      ggc_mark_tree (TYPE_MAX_VALUE (t));
+      ggc_mark_tree (TYPE_NEXT_VARIANT (t));
+      ggc_mark_tree (TYPE_MAIN_VARIANT (t));
+      ggc_mark_tree (TYPE_BINFO (t));
+      ggc_mark_tree (TYPE_NONCOPIED_PARTS (t));
+      ggc_mark_tree (TYPE_CONTEXT (t));
+      lang_mark_tree (t);
+      break;
+
+    case 'b': /* A lexical block.  */
+      ggc_mark_tree (BLOCK_VARS (t));
+      ggc_mark_tree (BLOCK_TYPE_TAGS (t));
+      ggc_mark_tree (BLOCK_SUBBLOCKS (t));
+      ggc_mark_tree (BLOCK_SUPERCONTEXT (t));
+      ggc_mark_tree (BLOCK_ABSTRACT_ORIGIN (t));
+      ggc_mark_rtx (BLOCK_END_NOTE (t));
+      break;
+
+    case 'c': /* A constant.  */
+      ggc_mark_rtx (TREE_CST_RTL (t));
+      break;
+
+    case 'r': case '<': case '1':
+    case '2': case 'e': case 's': /* Expressions.  */
+      {
+       int i = tree_code_length[TREE_CODE (t)];
+       while (--i >= 0)
+         ggc_mark_tree (TREE_OPERAND (t, i));
+       break;
+      }
+    }
+}
+
+void
+ggc_mark_string (s)
+     char *s;
+{
+  unsigned int *magic = (unsigned int *)s - 1;
+
+  if (s == NULL)
+    return;
+
+  if ((*magic & ~(unsigned)1) != GGC_STRING_MAGIC)
+    return;   /* abort? */
+  *magic = GGC_STRING_MAGIC | 1;
+}
+
+/* The top level mark-and-sweep routine.  */
+
+void
+ggc_collect ()
+{
+  struct ggc_rtx *r, **rp;
+  struct ggc_rtvec *v, **vp;
+  struct ggc_tree *t, **tp;
+  struct ggc_string *s, **sp;
+  struct ggc_root *x;
+  int time, n_rtxs, n_trees, n_vecs, n_strings;
+
+#ifndef ENABLE_CHECKING
+  /* See if it's even worth our while.  */
+  if (bytes_alloced_since_gc < 64*1024)
+    return;
+#endif
+
+  if (!quiet_flag)
+    fputs (" {GC ", stderr);
+
+  time = get_run_time ();
+
+  /* Clean out all of the GC marks.  */
+  for (r = rtxs; r != NULL; r = r->chain)
+    r->rtx.gc_mark = 0;
+  for (v = vecs; v != NULL; v = v->chain)
+    v->vec.gc_mark = 0;
+  for (t = trees; t != NULL; t = t->chain)
+    t->tree.common.gc_mark = 0;
+  for (s = strings; s != NULL; s = s->chain)
+    s->magic_mark = GGC_STRING_MAGIC;
+
+  /* Mark through all the roots.  */
+  for (x = roots; x != NULL; x = x->next)
+    {
+      char *elt = x->base;
+      int s = x->size, n = x->nelt;
+      void (*cb)(void *) = x->cb;
+      int i;
+
+      for (i = 0; i < n; ++i, elt += s)
+       (*cb)(elt);
+    }
+
+  /* Sweep the resulting dead nodes.  */
+  rp = &rtxs, r = rtxs, n_rtxs = 0;
+  while (r != NULL)
+    {
+      struct ggc_rtx *chain = r->chain;
+      if (!r->rtx.gc_mark)
+        {
+         ggc_free_rtx (r);
+         *rp = chain;
+         n_rtxs++;
+        }
+      else
+       rp = &r->chain;
+      r = chain;
+    }
+  *rp = NULL;
+  n_rtxs_collected += n_rtxs;
+
+  vp = &vecs, v = vecs, n_vecs = 0;
+  while (v != NULL)
+    {
+      struct ggc_rtvec *chain = v->chain;
+      if (!v->vec.gc_mark)
+        {
+         ggc_free_rtvec (v);
+         *vp = chain;
+         n_vecs++;
+        }
+      else
+       vp = &v->chain;
+      v = chain;
+    }
+  *vp = NULL;
+  n_vecs_collected += n_vecs;
+
+  tp = &trees, t = trees, n_trees = 0;
+  while (t != NULL)
+    {
+      struct ggc_tree *chain = t->chain;
+      if (!t->tree.common.gc_mark)
+        {
+         ggc_free_tree (t);
+         *tp = chain;
+         n_trees++;
+        }
+      else
+       tp = &t->chain;
+      t = chain;
+    }
+  *tp = NULL;
+  n_trees_collected += n_trees;
+
+  sp = &strings, s = strings, n_strings = 0;
+  while (s != NULL)
+    {
+      struct ggc_string *chain = s->chain;
+      if (!(s->magic_mark & 1))
+        {
+         ggc_free_string (s);
+         *sp = chain;
+         n_strings++;
+        }
+      else
+       sp = &s->chain;
+      s = chain;
+    }
+  *sp = NULL;
+  n_strings_collected += n_strings;
+
+  gc_time += time = get_run_time () - time;
+
+  if (!quiet_flag)
+    {
+      time = (time + 500) / 1000;
+      fprintf (stderr, "%d,%d,%d,%d %d.%03d}", n_rtxs, n_vecs, n_trees,
+              n_strings, time / 1000, time % 1000);
+    }
+}
+
+/* Manipulate global roots that are needed between calls to gc.  */
+
+void
+ggc_add_root (base, nelt, size, cb)
+     void *base;
+     int nelt, size;
+     void (*cb) PROTO ((void *));
+{
+  struct ggc_root *x = (struct ggc_root *) xmalloc (sizeof(*x));
+
+  x->next = roots;
+  x->base = base;
+  x->nelt = nelt;
+  x->size = size;
+  x->cb = cb;
+
+  roots = x;
+}
+
+void
+ggc_add_rtx_root (base, nelt)
+     rtx *base;
+     int nelt;
+{
+  ggc_add_root (base, nelt, sizeof(rtx), ggc_mark_rtx_ptr);
+}
+
+void
+ggc_add_tree_root (base, nelt)
+     tree *base;
+     int nelt;
+{
+  ggc_add_root (base, nelt, sizeof(tree), ggc_mark_tree_ptr);
+}
+
+void
+ggc_del_root (base)
+     void *base;
+{
+  struct ggc_root *x, **p;
+
+  p = &roots, x = roots;
+  while (x)
+    {
+      if (x->base == base)
+       {
+         *p = x->next;
+         free (x);
+         return;
+       }
+      p = &x->next;
+      x = x->next;
+    }
+
+  abort();
+}
+
+static void
+ggc_mark_rtx_ptr (elt)
+     void *elt;
+{
+  ggc_mark_rtx (*(rtx *)elt);
+}
+
+static void
+ggc_mark_tree_ptr (elt)
+     void *elt;
+{
+  ggc_mark_tree (*(tree *)elt);
+}
+
+#ifdef GGC_DUMP
+/* Don't enable this unless you want a really really lot of data.  */
+static void __attribute__((constructor))
+init(void)
+{
+  dump = fopen ("zgcdump", "w");
+  setlinebuf (dump);
+}
+#endif
+
+#if 0
+/* GDB really should have a memory search function.  Since this is just
+   for initial debugging, I won't even pretend to get the __data_start
+   to work on any but alpha-dec-linux-gnu.  */
+static void **
+search_data(void **start, void *target)
+{
+  extern void *__data_start[];
+  void **_end = (void **)sbrk(0);
+
+  if (start == NULL)
+    start = __data_start;
+  while (start < _end)
+    {
+      if (*start == target)
+        return start;
+      start++;
+    }
+  return NULL;
+}
+#endif
diff --git a/gcc/ggc.h b/gcc/ggc.h
new file mode 100644 (file)
index 0000000..bb0be13
--- /dev/null
+++ b/gcc/ggc.h
@@ -0,0 +1,72 @@
+/* Garbage collection for the GNU compiler.
+   Copyright (C) 1998 Free Software Foundation, Inc.
+
+   This file is part of GNU CC.
+
+   GNU CC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   GNU CC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "gansidecl.h"
+
+/* Symbols are marked with `ggc' for `gcc gc' so as not to interfere with
+   an external gc library that might be linked in.  */
+
+/* Startup */
+
+extern void init_ggc PROTO ((void));
+
+/* Allocation.  */
+
+struct rtx_def *ggc_alloc_rtx PROTO ((int nslots));
+struct rtvec_def *ggc_alloc_rtvec PROTO ((int nelt));
+union tree_node *ggc_alloc_tree PROTO ((int length));
+char *ggc_alloc_string PROTO ((const char *contents, int length));
+
+/* Invoke the collector.  This is really just a hint, but in the case of
+   the simple collector, the only time it will happen.  */
+
+void ggc_collect PROTO ((void));
+
+/* Manipulate global roots that are needed between calls to gc.  */
+void ggc_add_root PROTO ((void *base, int nelt, int size,
+                          void (*)(void *)));
+void ggc_add_rtx_root PROTO ((struct rtx_def **, int nelt));
+void ggc_add_tree_root PROTO ((union tree_node **, int nelt));
+void ggc_del_root PROTO ((void *base));
+
+/* Mark nodes from the gc_add_root callback.  */
+void ggc_mark_rtx PROTO ((struct rtx_def *));
+void ggc_mark_rtvec PROTO ((struct rtvec_def *));
+void ggc_mark_tree PROTO ((union tree_node *));
+void ggc_mark_string PROTO ((char *));
+
+/* Callbacks to the languages.  */
+
+/* This is the language's opportunity to mark nodes held through
+   the lang_specific hooks in the tree.  */
+void lang_mark_tree PROTO ((union tree_node *));
+
+/* And similarly to free that data when the tree node is released.  */
+void lang_cleanup_tree PROTO ((union tree_node *));
+
+/* Mark functions for various structs scattered about.  */
+
+void mark_temp_slot PROTO ((void *));
+void mark_function_chain PROTO ((void *));
+void mark_eh_state PROTO ((void *));
+void mark_stmt_state PROTO ((void *));
+void mark_emit_state PROTO ((void *));
+void mark_varasm_state PROTO ((void *));
+void mark_optab PROTO ((void *));
index acb9f756bb86496d6c95d084093485f46599fe3c..d680ed71059beb167fbfc66f1d9eaaf67c57d062 100644 (file)
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -102,13 +102,13 @@ typedef struct rtx_def
 {
 #ifdef ONLY_INT_FIELDS
 #ifdef CODE_FIELD_BUG
-  unsigned int code : 16;
+  unsigned int code : 15;
 #else
   unsigned short code;
 #endif
 #else
   /* The kind of expression this is.  */
-  enum rtx_code code : 16;
+  enum rtx_code code : 15;
 #endif
   /* The kind of value the expression has.  */
 #ifdef ONLY_INT_FIELDS
@@ -171,6 +171,10 @@ typedef struct rtx_def
      1 in a MEM if the MEM refers to a scalar, rather than a member of
      an aggregate.  */
   unsigned frame_related : 1;
+
+  /* Used by the garbage collector.  */
+  unsigned gc_mark : 1;
+
   /* The first element of the operands of this rtx.
      The number of operands and their types are controlled
      by the `code' field, according to rtl.def.  */
@@ -202,6 +206,7 @@ typedef struct rtx_def
 
 typedef struct rtvec_def{
   int num_elem;                /* number of elements */
+  int gc_mark;
   struct rtx_def *elem[1];
 } *rtvec;
 
index 3534da7f6e970cf4647fa9d4be728a035c180fba..266c64c4d7af639bdcbd08de29a8cf67524658b0 100644 (file)
@@ -54,6 +54,7 @@ Boston, MA 02111-1307, USA.  */
 #include "expr.h"
 #include "basic-block.h"
 #include "intl.h"
+#include "ggc.h"
 
 #ifdef DWARF_DEBUGGING_INFO
 #include "dwarfout.h"
@@ -1350,6 +1351,8 @@ int stack_reg_time;
 int final_time;
 int symout_time;
 int dump_time;
+int gc_time;
+int all_time;
 \f
 /* Return time used so far, in microseconds.  */
 
@@ -1429,8 +1432,9 @@ print_time (str, total)
      int total;
 {
   fprintf (stderr,
-          "time in %s: %d.%06d\n",
-          str, total / 1000000, total % 1000000);
+          "time in %s: %d.%06d (%.0f%%)\n",
+          str, total / 1000000, total % 1000000,
+          (double)total / (double)all_time * 100.0);
 }
 
 /* Count an error or warning.  Return 1 if the message should be printed.  */
@@ -3446,9 +3450,11 @@ compile_file (name)
 
   if (! quiet_flag)
     {
+      all_time = get_run_time ();
+
       fprintf (stderr,"\n");
-      print_time ("parse", parse_time);
 
+      print_time ("parse", parse_time);
       print_time ("integration", integration_time);
       print_time ("jump", jump_time);
       print_time ("cse", cse_time);
@@ -3473,6 +3479,7 @@ compile_file (name)
       print_time ("varconst", varconst_time);
       print_time ("symout", symout_time);
       print_time ("dump", dump_time);
+      print_time ("gc", gc_time);
     }
 }
 \f
@@ -3772,7 +3779,7 @@ rest_of_compilation (decl)
   /* See if we have allocated stack slots that are not directly addressable.
      If so, scan all the insns and create explicit address computation
      for all references to such slots.  */
-/*   fixup_stack_slots (); */
+  /* fixup_stack_slots (); */
 
   /* Find all the EH handlers.  */
   find_exception_handler_labels ();
index e5a9ebf0a3055d4e09af0d7384d95ce10a8575a2..44d6f043b5d8da5fae995a16a7688ffc93dd2723 100644 (file)
@@ -194,7 +194,10 @@ struct tree_common
   unsigned lang_flag_4 : 1;
   unsigned lang_flag_5 : 1;
   unsigned lang_flag_6 : 1;
-  /* There is room for three more flags.  */
+
+  unsigned gc_mark : 1;
+
+  /* There is room for two more flags.  */
 };
 
 /* The following table lists the uses of each of the above flags and