diff options
author | mmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4> | 1999-09-04 18:25:41 +0000 |
---|---|---|
committer | mmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4> | 1999-09-04 18:25:41 +0000 |
commit | 05513b452c469f1b9600c9b2cca224a7dd32062d (patch) | |
tree | 068cd2859713068d2e717951d385915d6b99a4df /gcc | |
parent | 7086d72a013ca952df8d8d1aae2fb61e5a24d1a5 (diff) | |
download | gcc-05513b452c469f1b9600c9b2cca224a7dd32062d.tar.gz |
* 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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@29106 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 17 | ||||
-rw-r--r-- | gcc/Makefile.in | 13 | ||||
-rw-r--r-- | gcc/emit-rtl.c | 22 | ||||
-rw-r--r-- | gcc/ggc-none.c | 58 | ||||
-rw-r--r-- | gcc/ggc-simple.c | 714 | ||||
-rw-r--r-- | gcc/ggc.h | 72 | ||||
-rw-r--r-- | gcc/rtl.h | 9 | ||||
-rw-r--r-- | gcc/toplev.c | 15 | ||||
-rw-r--r-- | gcc/tree.h | 5 |
9 files changed, 906 insertions, 19 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4e78651c4c5..ed79892a25c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 164d939368d..333da82d495 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -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 diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index 8d3f2fae61d..c16ffe4da40 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -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 index 00000000000..5fff1045fab --- /dev/null +++ b/gcc/ggc-none.c @@ -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 index 00000000000..3ce7bcb596b --- /dev/null +++ b/gcc/ggc-simple.c @@ -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 index 00000000000..bb0be13623e --- /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 *)); diff --git a/gcc/rtl.h b/gcc/rtl.h index acb9f756bb8..d680ed71059 100644 --- 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; diff --git a/gcc/toplev.c b/gcc/toplev.c index 3534da7f6e9..266c64c4d7a 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -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; /* 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); } } @@ -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 (); diff --git a/gcc/tree.h b/gcc/tree.h index e5a9ebf0a30..44d6f043b5d 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -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 |