Commit 4c160717 by Richard Kenner Committed by Richard Kenner

fold-const.c (hashtab.h): Include.

	* fold-const.c (hashtab.h): Include.
	(int_const_binop): Remove FORSIZE arg and compute from type; all
	callers changed.
	Call size_int_type_wide for all single-word constants.
	(size_htab_hash, size_htab_eq): New functions.
	(size_int_type_wide): Rework to use hash table.
	* ggc-common.c (hashtab.h): Include.
	(struct d_htab_root): New struct.
	(d_htab_roots): New variable.
	(ggc_add_deletable_htab, ggc_htab_delete): New functions
	(ggc_mark_roots): Handle deletable htabs.
	* ggc-page.c (ggc_marked_p): New function.
	* ggc-simple.c (ggc_marked_p): Likewise.
	* ggc.h: Reformatting throughout.
	(ggc_marked_p, ggc_add_deletable_htab): New declarations.
	* tree.c (init_obstacks): Make type_hash_table a deletable root.
	(type_hash_add): Allocate struct type_hash from GC memory.
	(mark_hash_entry, mark_type_hash): Deleted.
	(type_hash_marked_p, type_hash_mark): New functions.
	* Makefile.in (ggc-common.o, fold-const.o): Include hashtab.h.

From-SVN: r45710
parent c762ab6e
Thu Sep 20 09:00:27 2001 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
* fold-const.c (hashtab.h): Include.
(int_const_binop): Remove FORSIZE arg and compute from type; all
callers changed.
Call size_int_type_wide for all single-word constants.
(size_htab_hash, size_htab_eq): New functions.
(size_int_type_wide): Rework to use hash table.
* ggc-common.c (hashtab.h): Include.
(struct d_htab_root): New struct.
(d_htab_roots): New variable.
(ggc_add_deletable_htab, ggc_htab_delete): New functions
(ggc_mark_roots): Handle deletable htabs.
* ggc-page.c (ggc_marked_p): New function.
* ggc-simple.c (ggc_marked_p): Likewise.
* ggc.h: Reformatting throughout.
(ggc_marked_p, ggc_add_deletable_htab): New declarations.
* tree.c (init_obstacks): Make type_hash_table a deletable root.
(type_hash_add): Allocate struct type_hash from GC memory.
(mark_hash_entry, mark_type_hash): Deleted.
(type_hash_marked_p, type_hash_mark): New functions.
* Makefile.in (ggc-common.o, fold-const.o): Include hashtab.h.
Thu Sep 20 12:49:34 2001 J"orn Rennecke <amylaar@redhat.com> Thu Sep 20 12:49:34 2001 J"orn Rennecke <amylaar@redhat.com>
* sh.c (shiftcosts): Don't use shiftcosts array for modes wider * sh.c (shiftcosts): Don't use shiftcosts array for modes wider
......
...@@ -1310,7 +1310,7 @@ dumpvers: dumpvers.c ...@@ -1310,7 +1310,7 @@ dumpvers: dumpvers.c
version.o: version.c version.h version.o: version.c version.h
ggc-common.o: ggc-common.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) \ ggc-common.o: ggc-common.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) \
flags.h $(GGC_H) varray.h hash.h $(TM_P_H) flags.h $(GGC_H) varray.h hash.h $(HASHTAB_H) $(TM_P_H)
ggc-simple.o: ggc-simple.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \ ggc-simple.o: ggc-simple.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
$(GGC_H) varray.h $(TIMEVAR_H) $(TM_P_H) $(GGC_H) varray.h $(TIMEVAR_H) $(TM_P_H)
...@@ -1346,8 +1346,8 @@ tree.o : tree.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) flags.h function.h toplev.h \ ...@@ -1346,8 +1346,8 @@ tree.o : tree.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) flags.h function.h toplev.h \
print-tree.o : print-tree.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(GGC_H) print-tree.o : print-tree.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(GGC_H)
stor-layout.o : stor-layout.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) flags.h \ stor-layout.o : stor-layout.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) flags.h \
function.h $(EXPR_H) $(RTL_H) toplev.h $(GGC_H) $(TM_P_H) function.h $(EXPR_H) $(RTL_H) toplev.h $(GGC_H) $(TM_P_H)
fold-const.o : fold-const.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) flags.h toplev.h \ fold-const.o : fold-const.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) flags.h \
$(EXPR_H) $(RTL_H) $(GGC_H) $(TM_P_H) toplev.h $(HASHTAB_H) $(EXPR_H) $(RTL_H) $(GGC_H) $(TM_P_H)
diagnostic.o : diagnostic.c diagnostic.h real.h diagnostic.def \ diagnostic.o : diagnostic.c diagnostic.h real.h diagnostic.def \
$(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(TM_P_H) flags.h $(GGC_H) \ $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(TM_P_H) flags.h $(GGC_H) \
input.h toplev.h intl.h input.h toplev.h intl.h
......
...@@ -51,6 +51,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA ...@@ -51,6 +51,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "tm_p.h" #include "tm_p.h"
#include "toplev.h" #include "toplev.h"
#include "ggc.h" #include "ggc.h"
#include "hashtab.h"
static void encode PARAMS ((HOST_WIDE_INT *, static void encode PARAMS ((HOST_WIDE_INT *,
unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
...@@ -65,9 +66,11 @@ static tree negate_expr PARAMS ((tree)); ...@@ -65,9 +66,11 @@ static tree negate_expr PARAMS ((tree));
static tree split_tree PARAMS ((tree, enum tree_code, tree *, tree *, static tree split_tree PARAMS ((tree, enum tree_code, tree *, tree *,
int)); int));
static tree associate_trees PARAMS ((tree, tree, enum tree_code, tree)); static tree associate_trees PARAMS ((tree, tree, enum tree_code, tree));
static tree int_const_binop PARAMS ((enum tree_code, tree, tree, int, int)); static tree int_const_binop PARAMS ((enum tree_code, tree, tree, int));
static void const_binop_1 PARAMS ((PTR)); static void const_binop_1 PARAMS ((PTR));
static tree const_binop PARAMS ((enum tree_code, tree, tree, int)); static tree const_binop PARAMS ((enum tree_code, tree, tree, int));
static hashval_t size_htab_hash PARAMS ((const void *));
static int size_htab_eq PARAMS ((const void *, const void *));
static void fold_convert_1 PARAMS ((PTR)); static void fold_convert_1 PARAMS ((PTR));
static tree fold_convert PARAMS ((tree, tree)); static tree fold_convert PARAMS ((tree, tree));
static enum tree_code invert_tree_comparison PARAMS ((enum tree_code)); static enum tree_code invert_tree_comparison PARAMS ((enum tree_code));
...@@ -1478,14 +1481,13 @@ associate_trees (t1, t2, code, type) ...@@ -1478,14 +1481,13 @@ associate_trees (t1, t2, code, type)
/* Combine two integer constants ARG1 and ARG2 under operation CODE /* Combine two integer constants ARG1 and ARG2 under operation CODE
to produce a new constant. to produce a new constant.
If NOTRUNC is nonzero, do not truncate the result to fit the data type. If NOTRUNC is nonzero, do not truncate the result to fit the data type. */
If FORSIZE is nonzero, compute overflow for unsigned types. */
static tree static tree
int_const_binop (code, arg1, arg2, notrunc, forsize) int_const_binop (code, arg1, arg2, notrunc)
enum tree_code code; enum tree_code code;
register tree arg1, arg2; register tree arg1, arg2;
int notrunc, forsize; int notrunc;
{ {
unsigned HOST_WIDE_INT int1l, int2l; unsigned HOST_WIDE_INT int1l, int2l;
HOST_WIDE_INT int1h, int2h; HOST_WIDE_INT int1h, int2h;
...@@ -1494,7 +1496,10 @@ int_const_binop (code, arg1, arg2, notrunc, forsize) ...@@ -1494,7 +1496,10 @@ int_const_binop (code, arg1, arg2, notrunc, forsize)
unsigned HOST_WIDE_INT garbagel; unsigned HOST_WIDE_INT garbagel;
HOST_WIDE_INT garbageh; HOST_WIDE_INT garbageh;
register tree t; register tree t;
int uns = TREE_UNSIGNED (TREE_TYPE (arg1)); tree type = TREE_TYPE (arg1);
int uns = TREE_UNSIGNED (type);
int is_sizetype
= (TREE_CODE (type) == INTEGER_TYPE && TYPE_IS_SIZETYPE (type));
int overflow = 0; int overflow = 0;
int no_overflow = 0; int no_overflow = 0;
...@@ -1527,7 +1532,7 @@ int_const_binop (code, arg1, arg2, notrunc, forsize) ...@@ -1527,7 +1532,7 @@ int_const_binop (code, arg1, arg2, notrunc, forsize)
/* It's unclear from the C standard whether shifts can overflow. /* It's unclear from the C standard whether shifts can overflow.
The following code ignores overflow; perhaps a C standard The following code ignores overflow; perhaps a C standard
interpretation ruling is needed. */ interpretation ruling is needed. */
lshift_double (int1l, int1h, int2l, TYPE_PRECISION (TREE_TYPE (arg1)), lshift_double (int1l, int1h, int2l, TYPE_PRECISION (type),
&low, &hi, !uns); &low, &hi, !uns);
no_overflow = 1; no_overflow = 1;
break; break;
...@@ -1535,7 +1540,7 @@ int_const_binop (code, arg1, arg2, notrunc, forsize) ...@@ -1535,7 +1540,7 @@ int_const_binop (code, arg1, arg2, notrunc, forsize)
case RROTATE_EXPR: case RROTATE_EXPR:
int2l = - int2l; int2l = - int2l;
case LROTATE_EXPR: case LROTATE_EXPR:
lrotate_double (int1l, int1h, int2l, TYPE_PRECISION (TREE_TYPE (arg1)), lrotate_double (int1l, int1h, int2l, TYPE_PRECISION (type),
&low, &hi); &low, &hi);
break; break;
...@@ -1583,8 +1588,7 @@ int_const_binop (code, arg1, arg2, notrunc, forsize) ...@@ -1583,8 +1588,7 @@ int_const_binop (code, arg1, arg2, notrunc, forsize)
low = 1, hi = 0; low = 1, hi = 0;
break; break;
} }
overflow = div_and_round_double (code, uns, overflow = div_and_round_double (code, uns, int1l, int1h, int2l, int2h,
int1l, int1h, int2l, int2h,
&low, &hi, &garbagel, &garbageh); &low, &hi, &garbagel, &garbageh);
break; break;
...@@ -1632,9 +1636,14 @@ int_const_binop (code, arg1, arg2, notrunc, forsize) ...@@ -1632,9 +1636,14 @@ int_const_binop (code, arg1, arg2, notrunc, forsize)
abort (); abort ();
} }
if (forsize && hi == 0 && low < 10000 /* If this is for a sizetype, can be represented as one (signed)
HOST_WIDE_INT word, and doesn't overflow, use size_int since it caches
constants. */
if (is_sizetype
&& ((hi == 0 && (HOST_WIDE_INT) low >= 0)
|| (hi == -1 && (HOST_WIDE_INT) low < 0))
&& overflow == 0 && ! TREE_OVERFLOW (arg1) && ! TREE_OVERFLOW (arg2)) && overflow == 0 && ! TREE_OVERFLOW (arg1) && ! TREE_OVERFLOW (arg2))
return size_int_type_wide (low, TREE_TYPE (arg1)); return size_int_type_wide (low, type);
else else
{ {
t = build_int_2 (low, hi); t = build_int_2 (low, hi);
...@@ -1642,14 +1651,16 @@ int_const_binop (code, arg1, arg2, notrunc, forsize) ...@@ -1642,14 +1651,16 @@ int_const_binop (code, arg1, arg2, notrunc, forsize)
} }
TREE_OVERFLOW (t) TREE_OVERFLOW (t)
= ((notrunc ? (!uns || forsize) && overflow = ((notrunc
: force_fit_type (t, (!uns || forsize) && overflow) && ! no_overflow) ? (!uns || is_sizetype) && overflow
: (force_fit_type (t, (!uns || is_sizetype) && overflow)
&& ! no_overflow))
| TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg1)
| TREE_OVERFLOW (arg2)); | TREE_OVERFLOW (arg2));
/* If we're doing a size calculation, unsigned arithmetic does overflow. /* If we're doing a size calculation, unsigned arithmetic does overflow.
So check if force_fit_type truncated the value. */ So check if force_fit_type truncated the value. */
if (forsize if (is_sizetype
&& ! TREE_OVERFLOW (t) && ! TREE_OVERFLOW (t)
&& (TREE_INT_CST_HIGH (t) != hi && (TREE_INT_CST_HIGH (t) != hi
|| TREE_INT_CST_LOW (t) != low)) || TREE_INT_CST_LOW (t) != low))
...@@ -1740,7 +1751,7 @@ const_binop (code, arg1, arg2, notrunc) ...@@ -1740,7 +1751,7 @@ const_binop (code, arg1, arg2, notrunc)
STRIP_NOPS (arg2); STRIP_NOPS (arg2);
if (TREE_CODE (arg1) == INTEGER_CST) if (TREE_CODE (arg1) == INTEGER_CST)
return int_const_binop (code, arg1, arg2, notrunc, 0); return int_const_binop (code, arg1, arg2, notrunc);
#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) #if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
if (TREE_CODE (arg1) == REAL_CST) if (TREE_CODE (arg1) == REAL_CST)
...@@ -1865,6 +1876,39 @@ const_binop (code, arg1, arg2, notrunc) ...@@ -1865,6 +1876,39 @@ const_binop (code, arg1, arg2, notrunc)
} }
return 0; return 0;
} }
/* These are the hash table functions for the hash table of INTEGER_CST
nodes of a sizetype. */
/* Return the hash code code X, an INTEGER_CST. */
static hashval_t
size_htab_hash (x)
const void *x;
{
tree t = (tree) x;
return (TREE_INT_CST_HIGH (t) ^ TREE_INT_CST_LOW (t)
^ (hashval_t) ((long) TREE_TYPE (t) >> 3)
^ (TREE_OVERFLOW (t) << 20));
}
/* Return non-zero if the value represented by *X (an INTEGER_CST tree node)
is the same as that given by *Y, which is the same. */
static int
size_htab_eq (x, y)
const void *x;
const void *y;
{
tree xt = (tree) x;
tree yt = (tree) y;
return (TREE_INT_CST_HIGH (xt) == TREE_INT_CST_HIGH (yt)
&& TREE_INT_CST_LOW (xt) == TREE_INT_CST_LOW (yt)
&& TREE_TYPE (xt) == TREE_TYPE (yt)
&& TREE_OVERFLOW (xt) == TREE_OVERFLOW (yt));
}
/* Return an INTEGER_CST with value whose low-order HOST_BITS_PER_WIDE_INT /* Return an INTEGER_CST with value whose low-order HOST_BITS_PER_WIDE_INT
bits are given by NUMBER and of the sizetype represented by KIND. */ bits are given by NUMBER and of the sizetype represented by KIND. */
...@@ -1884,40 +1928,38 @@ size_int_type_wide (number, type) ...@@ -1884,40 +1928,38 @@ size_int_type_wide (number, type)
HOST_WIDE_INT number; HOST_WIDE_INT number;
tree type; tree type;
{ {
/* Type-size nodes already made for small sizes. */ static htab_t size_htab = 0;
static tree size_table[2048 + 1]; static tree new_const = 0;
static int init_p = 0; PTR *slot;
tree t;
if (! init_p) if (size_htab == 0)
{ {
ggc_add_tree_root ((tree *) size_table, size_htab = htab_create (1024, size_htab_hash, size_htab_eq, NULL);
sizeof size_table / sizeof (tree)); ggc_add_deletable_htab (size_htab, NULL, NULL);
init_p = 1; new_const = make_node (INTEGER_CST);
ggc_add_tree_root (&new_const, 1);
} }
/* If this is a positive number that fits in the table we use to hold /* Adjust NEW_CONST to be the constant we want. If it's already in the
cached entries, see if it is already in the table and put it there hash table, we return the value from the hash table. Otherwise, we
if not. */ place that in the hash table and make a new node for the next time. */
if (number >= 0 && number < (int) ARRAY_SIZE (size_table)) TREE_INT_CST_LOW (new_const) = number;
TREE_INT_CST_HIGH (new_const) = number < 0 ? -1 : 0;
TREE_TYPE (new_const) = type;
TREE_OVERFLOW (new_const) = TREE_CONSTANT_OVERFLOW (new_const)
= force_fit_type (new_const, 0);
slot = htab_find_slot (size_htab, new_const, INSERT);
if (*slot == 0)
{ {
if (size_table[number] != 0) tree t = new_const;
for (t = size_table[number]; t != 0; t = TREE_CHAIN (t))
if (TREE_TYPE (t) == type)
return t;
t = build_int_2 (number, 0);
TREE_TYPE (t) = type;
TREE_CHAIN (t) = size_table[number];
size_table[number] = t;
*slot = (PTR) new_const;
new_const = make_node (INTEGER_CST);
return t; return t;
} }
else
t = build_int_2 (number, number < 0 ? -1 : 0); return (tree) *slot;
TREE_TYPE (t) = type;
TREE_OVERFLOW (t) = TREE_CONSTANT_OVERFLOW (t) = force_fit_type (t, 0);
return t;
} }
/* Combine operands OP1 and OP2 with arithmetic operation CODE. CODE /* Combine operands OP1 and OP2 with arithmetic operation CODE. CODE
...@@ -1949,7 +1991,7 @@ size_binop (code, arg0, arg1) ...@@ -1949,7 +1991,7 @@ size_binop (code, arg0, arg1)
return arg1; return arg1;
/* Handle general case of two integer constants. */ /* Handle general case of two integer constants. */
return int_const_binop (code, arg0, arg1, 0, 1); return int_const_binop (code, arg0, arg1, 0);
} }
if (arg0 == error_mark_node || arg1 == error_mark_node) if (arg0 == error_mark_node || arg1 == error_mark_node)
......
...@@ -27,6 +27,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA ...@@ -27,6 +27,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "tree.h" #include "tree.h"
#include "tm_p.h" #include "tm_p.h"
#include "hash.h" #include "hash.h"
#include "hashtab.h"
#include "varray.h" #include "varray.h"
#include "ggc.h" #include "ggc.h"
...@@ -47,9 +48,10 @@ static void ggc_mark_tree_ptr PARAMS ((void *)); ...@@ -47,9 +48,10 @@ static void ggc_mark_tree_ptr PARAMS ((void *));
static void ggc_mark_rtx_varray_ptr PARAMS ((void *)); static void ggc_mark_rtx_varray_ptr PARAMS ((void *));
static void ggc_mark_tree_varray_ptr PARAMS ((void *)); static void ggc_mark_tree_varray_ptr PARAMS ((void *));
static void ggc_mark_tree_hash_table_ptr PARAMS ((void *)); static void ggc_mark_tree_hash_table_ptr PARAMS ((void *));
static int ggc_htab_delete PARAMS ((void **, void *));
static void ggc_mark_trees PARAMS ((void)); static void ggc_mark_trees PARAMS ((void));
static bool ggc_mark_tree_hash_table_entry PARAMS ((struct hash_entry *, static bool ggc_mark_tree_hash_table_entry PARAMS ((struct hash_entry *,
hash_table_key)); hash_table_key));
/* Maintain global roots that are preserved during GC. */ /* Maintain global roots that are preserved during GC. */
...@@ -166,12 +168,79 @@ ggc_del_root (base) ...@@ -166,12 +168,79 @@ ggc_del_root (base)
abort(); abort();
} }
/* Add a hash table to be scanned when all roots have been processed. We
delete any entry in the table that has not been marked. */
struct d_htab_root
{
struct d_htab_root *next;
htab_t htab;
ggc_htab_marked_p marked_p;
ggc_htab_mark mark;
};
static struct d_htab_root *d_htab_roots;
/* Add X, an htab, to a list of htabs that contain objects which are allocated
from GC memory. Once all other roots are marked, we check each object in
the htab to see if it has already been marked. If not, it is deleted.
MARKED_P, if specified, is a function that returns 1 if the entry is to
be considered as "marked". If not present, the data structure pointed to
by the htab slot is tested. This function should be supplied if some
other object (such as something pointed to by that object) should be tested
in which case the function tests whether that object (or objects) are
marked (using ggc_marked_p) and returns nonzero if it is.
MARK, if specified, is a function that is passed the contents of a slot
that has been determined to have been "marked" (via the above function)
and marks any other objects pointed to by that object. For example,
we might have a hash table of memory attribute blocks, which are pointed
to by a MEM RTL but have a pointer to a DECL. MARKED_P in that case will
not be specified because we want to know if the attribute block is pointed
to by the MEM, but MARK must be specified because if the block has been
marked, we need to mark the DECL. */
void
ggc_add_deletable_htab (x, marked_p, mark)
PTR x;
ggc_htab_marked_p marked_p;
ggc_htab_mark mark;
{
struct d_htab_root *r
= (struct d_htab_root *) xmalloc (sizeof (struct d_htab_root));
r->next = d_htab_roots;
r->htab = (htab_t) x;
r->marked_p = marked_p ? marked_p : ggc_marked_p;
r->mark = mark;
d_htab_roots = r;
}
/* Process a slot of an htab by deleting it if it has not been marked. */
static int
ggc_htab_delete (slot, info)
void **slot;
void *info;
{
struct d_htab_root *r = (struct d_htab_root *) info;
if (! (*r->marked_p) (*slot))
htab_clear_slot (r->htab, slot);
else if (r->mark)
(*r->mark) (*slot);
return 1;
}
/* Iterate through all registered roots and mark each element. */ /* Iterate through all registered roots and mark each element. */
void void
ggc_mark_roots () ggc_mark_roots ()
{ {
struct ggc_root* x; struct ggc_root *x;
struct d_htab_root *y;
VARRAY_TREE_INIT (ggc_pending_trees, 4096, "ggc_pending_trees"); VARRAY_TREE_INIT (ggc_pending_trees, 4096, "ggc_pending_trees");
...@@ -189,6 +258,16 @@ ggc_mark_roots () ...@@ -189,6 +258,16 @@ ggc_mark_roots ()
/* Mark all the queued up trees, and their children. */ /* Mark all the queued up trees, and their children. */
ggc_mark_trees (); ggc_mark_trees ();
VARRAY_FREE (ggc_pending_trees); VARRAY_FREE (ggc_pending_trees);
/* Now scan all hash tables that have objects which are to be deleted if
they are not already marked. Since these may mark more trees, we need
to reinitialize that varray. */
VARRAY_TREE_INIT (ggc_pending_trees, 1024, "ggc_pending_trees");
for (y = d_htab_roots; y != NULL; y = y->next)
htab_traverse (y->htab, ggc_htab_delete, (PTR) y);
ggc_mark_trees ();
VARRAY_FREE (ggc_pending_trees);
} }
/* R had not been previously marked, but has now been marked via /* R had not been previously marked, but has now been marked via
...@@ -463,7 +542,7 @@ ggc_mark_tree_varray (v) ...@@ -463,7 +542,7 @@ ggc_mark_tree_varray (v)
ggc_mark_tree (VARRAY_TREE (v, i)); ggc_mark_tree (VARRAY_TREE (v, i));
} }
/* Mark the hash table-entry HE. It's key field is really a tree. */ /* Mark the hash table-entry HE. Its key field is really a tree. */
static bool static bool
ggc_mark_tree_hash_table_entry (he, k) ggc_mark_tree_hash_table_entry (he, k)
......
...@@ -1001,6 +1001,35 @@ ggc_set_mark (p) ...@@ -1001,6 +1001,35 @@ ggc_set_mark (p)
return 0; return 0;
} }
/* Return 1 if P has been marked, zero otherwise.
P must have been allocated by the GC allocator; it mustn't point to
static objects, stack variables, or memory allocated with malloc. */
int
ggc_marked_p (p)
const void *p;
{
page_entry *entry;
unsigned bit, word;
unsigned long mask;
/* Look up the page on which the object is alloced. If the object
wasn't allocated by the collector, we'll probably die. */
entry = lookup_page_table_entry (p);
#ifdef ENABLE_CHECKING
if (entry == NULL)
abort ();
#endif
/* Calculate the index of the object on the page; this is its bit
position in the in_use_p bitmap. */
bit = (((const char *) p) - entry->page) / OBJECT_SIZE (entry->order);
word = bit / HOST_BITS_PER_LONG;
mask = (unsigned long) 1 << (bit % HOST_BITS_PER_LONG);
return entry->in_use_p[word] & mask;
}
/* Return the size of the gc-able object P. */ /* Return the size of the gc-able object P. */
size_t size_t
......
...@@ -228,6 +228,23 @@ ggc_set_mark (p) ...@@ -228,6 +228,23 @@ ggc_set_mark (p)
return 0; return 0;
} }
/* Return 1 if P has been marked, zero otherwise. */
int
ggc_marked_p (p)
const void *p;
{
struct ggc_mem *x;
x = (struct ggc_mem *) ((const char *)p - offsetof (struct ggc_mem, u));
#ifdef GGC_ALWAYS_VERIFY
if (! tree_lookup (x))
abort ();
#endif
return x->mark;
}
/* Return the size of the gc-able object P. */ /* Return the size of the gc-able object P. */
size_t size_t
......
...@@ -47,23 +47,39 @@ extern const char digit_vector[]; /* "0" .. "9" */ ...@@ -47,23 +47,39 @@ extern const char digit_vector[]; /* "0" .. "9" */
extern varray_type ggc_pending_trees; extern varray_type ggc_pending_trees;
/* Manipulate global roots that are needed between calls to gc. */ /* Manipulate global roots that are needed between calls to gc. */
void ggc_add_root PARAMS ((void *base, int nelt, int size, void (*)(void *))); extern void ggc_add_root PARAMS ((void *base, int nelt,
void ggc_add_rtx_root PARAMS ((struct rtx_def **, int nelt)); int size, void (*)(void *)));
void ggc_add_tree_root PARAMS ((union tree_node **, int nelt)); extern void ggc_add_rtx_root PARAMS ((struct rtx_def **, int nelt));
void ggc_add_rtx_varray_root PARAMS ((struct varray_head_tag **, int nelt)); extern void ggc_add_tree_root PARAMS ((union tree_node **,
void ggc_add_tree_varray_root PARAMS ((struct varray_head_tag **, int nelt)); int nelt));
void ggc_add_tree_hash_table_root PARAMS ((struct hash_table **, int nelt)); extern void ggc_add_rtx_varray_root PARAMS ((struct varray_head_tag **,
void ggc_del_root PARAMS ((void *base)); int nelt));
extern void ggc_add_tree_varray_root PARAMS ((struct varray_head_tag **,
int nelt));
extern void ggc_add_tree_hash_table_root PARAMS ((struct hash_table **,
int nelt));
extern void ggc_del_root PARAMS ((void *base));
/* Types used for mark test and marking functions, if specified, in call
below. */
typedef int (*ggc_htab_marked_p) PARAMS ((const void *));
typedef void (*ggc_htab_mark) PARAMS ((const void *));
/* Add a hash table to be scanned when all roots have been processed. We
delete any entry in the table that has not been marked. The argument is
really htab_t. */
extern void ggc_add_deletable_htab PARAMS ((PTR, ggc_htab_marked_p,
ggc_htab_mark));
/* Mark nodes from the gc_add_root callback. These functions follow /* Mark nodes from the gc_add_root callback. These functions follow
pointers to mark other objects too. */ pointers to mark other objects too. */
extern void ggc_mark_rtx_varray PARAMS ((struct varray_head_tag *)); extern void ggc_mark_rtx_varray PARAMS ((struct varray_head_tag *));
extern void ggc_mark_tree_varray PARAMS ((struct varray_head_tag *)); extern void ggc_mark_tree_varray PARAMS ((struct varray_head_tag *));
extern void ggc_mark_tree_hash_table PARAMS ((struct hash_table *)); extern void ggc_mark_tree_hash_table PARAMS ((struct hash_table *));
extern void ggc_mark_roots PARAMS ((void)); extern void ggc_mark_roots PARAMS ((void));
extern void ggc_mark_rtx_children PARAMS ((struct rtx_def *)); extern void ggc_mark_rtx_children PARAMS ((struct rtx_def *));
extern void ggc_mark_rtvec_children PARAMS ((struct rtvec_def *)); extern void ggc_mark_rtvec_children PARAMS ((struct rtvec_def *));
/* If EXPR is not NULL and previously unmarked, mark it and evaluate /* If EXPR is not NULL and previously unmarked, mark it and evaluate
to true. Otherwise evaluate to false. */ to true. Otherwise evaluate to false. */
...@@ -108,23 +124,23 @@ extern void ggc_mark_rtvec_children PARAMS ((struct rtvec_def *)); ...@@ -108,23 +124,23 @@ extern void ggc_mark_rtvec_children PARAMS ((struct rtvec_def *));
/* A GC implementation must provide these functions. */ /* A GC implementation must provide these functions. */
/* Initialize the garbage collector. */ /* Initialize the garbage collector. */
extern void init_ggc PARAMS ((void)); extern void init_ggc PARAMS ((void));
extern void init_stringpool PARAMS ((void)); extern void init_stringpool PARAMS ((void));
/* Start a new GGC context. Memory allocated in previous contexts /* Start a new GGC context. Memory allocated in previous contexts
will not be collected while the new context is active. */ will not be collected while the new context is active. */
extern void ggc_push_context PARAMS ((void)); extern void ggc_push_context PARAMS ((void));
/* Finish a GC context. Any uncollected memory in the new context /* Finish a GC context. Any uncollected memory in the new context
will be merged with the old context. */ will be merged with the old context. */
extern void ggc_pop_context PARAMS ((void)); extern void ggc_pop_context PARAMS ((void));
/* Allocation. */ /* Allocation. */
/* The internal primitive. */ /* The internal primitive. */
void *ggc_alloc PARAMS ((size_t)); extern void *ggc_alloc PARAMS ((size_t));
/* Like ggc_alloc, but allocates cleared memory. */ /* Like ggc_alloc, but allocates cleared memory. */
void *ggc_alloc_cleared PARAMS ((size_t)); extern void *ggc_alloc_cleared PARAMS ((size_t));
#define ggc_alloc_rtx(NSLOTS) \ #define ggc_alloc_rtx(NSLOTS) \
((struct rtx_def *) ggc_alloc (sizeof (struct rtx_def) \ ((struct rtx_def *) ggc_alloc (sizeof (struct rtx_def) \
...@@ -139,27 +155,33 @@ void *ggc_alloc_cleared PARAMS ((size_t)); ...@@ -139,27 +155,33 @@ void *ggc_alloc_cleared PARAMS ((size_t));
/* Allocate a gc-able string, and fill it with LENGTH bytes from CONTENTS. /* Allocate a gc-able string, and fill it with LENGTH bytes from CONTENTS.
If LENGTH is -1, then CONTENTS is assumed to be a If LENGTH is -1, then CONTENTS is assumed to be a
null-terminated string and the memory sized accordingly. */ null-terminated string and the memory sized accordingly. */
const char *ggc_alloc_string PARAMS ((const char *contents, int length)); extern const char *ggc_alloc_string PARAMS ((const char *contents,
int length));
/* Make a copy of S, in GC-able memory. */ /* Make a copy of S, in GC-able memory. */
#define ggc_strdup(S) ggc_alloc_string((S), -1) #define ggc_strdup(S) ggc_alloc_string((S), -1)
/* Invoke the collector. Garbage collection occurs only when this /* Invoke the collector. Garbage collection occurs only when this
function is called, not during allocations. */ function is called, not during allocations. */
void ggc_collect PARAMS ((void)); extern void ggc_collect PARAMS ((void));
/* Actually set the mark on a particular region of memory, but don't /* Actually set the mark on a particular region of memory, but don't
follow pointers. This function is called by ggc_mark_*. It follow pointers. This function is called by ggc_mark_*. It
returns zero if the object was not previously marked; non-zero if returns zero if the object was not previously marked; non-zero if
the object was already marked, or if, for any other reason, the object was already marked, or if, for any other reason,
pointers in this data structure should not be traversed. */ pointers in this data structure should not be traversed. */
int ggc_set_mark PARAMS ((const void *)); extern int ggc_set_mark PARAMS ((const void *));
/* Return 1 if P has been marked, zero otherwise.
P must have been allocated by the GC allocator; it mustn't point to
static objects, stack variables, or memory allocated with malloc. */
extern int ggc_marked_p PARAMS ((const void *));
/* Callbacks to the languages. */ /* Callbacks to the languages. */
/* This is the language's opportunity to mark nodes held through /* This is the language's opportunity to mark nodes held through
the lang_specific hooks in the tree. */ the lang_specific hooks in the tree. */
void lang_mark_tree PARAMS ((union tree_node *)); extern void lang_mark_tree PARAMS ((union tree_node *));
/* The FALSE_LABEL_STACK, declared in except.h, has language-dependent /* The FALSE_LABEL_STACK, declared in except.h, has language-dependent
semantics. If a front-end needs to mark the false label stack, it semantics. If a front-end needs to mark the false label stack, it
...@@ -169,12 +191,12 @@ extern void (*lang_mark_false_label_stack) PARAMS ((struct label_node *)); ...@@ -169,12 +191,12 @@ extern void (*lang_mark_false_label_stack) PARAMS ((struct label_node *));
/* Mark functions for various structs scattered about. */ /* Mark functions for various structs scattered about. */
void mark_eh_status PARAMS ((struct eh_status *)); void mark_eh_status PARAMS ((struct eh_status *));
void mark_emit_status PARAMS ((struct emit_status *)); void mark_emit_status PARAMS ((struct emit_status *));
void mark_expr_status PARAMS ((struct expr_status *)); void mark_expr_status PARAMS ((struct expr_status *));
void mark_stmt_status PARAMS ((struct stmt_status *)); void mark_stmt_status PARAMS ((struct stmt_status *));
void mark_varasm_status PARAMS ((struct varasm_status *)); void mark_varasm_status PARAMS ((struct varasm_status *));
void mark_optab PARAMS ((void *)); void mark_optab PARAMS ((void *));
/* Statistics. */ /* Statistics. */
...@@ -203,12 +225,12 @@ typedef struct ggc_statistics ...@@ -203,12 +225,12 @@ typedef struct ggc_statistics
} ggc_statistics; } ggc_statistics;
/* Return the number of bytes allocated at the indicated address. */ /* Return the number of bytes allocated at the indicated address. */
size_t ggc_get_size PARAMS ((const void *)); extern size_t ggc_get_size PARAMS ((const void *));
/* Used by the various collectors to gather and print statistics that /* Used by the various collectors to gather and print statistics that
do not depend on the collector in use. */ do not depend on the collector in use. */
void ggc_print_common_statistics PARAMS ((FILE *, ggc_statistics *)); extern void ggc_print_common_statistics PARAMS ((FILE *, ggc_statistics *));
/* Print allocation statistics. */ /* Print allocation statistics. */
extern void ggc_print_statistics PARAMS ((void)); extern void ggc_print_statistics PARAMS ((void));
void stringpool_statistics PARAMS ((void)); extern void stringpool_statistics PARAMS ((void));
...@@ -158,12 +158,12 @@ htab_t type_hash_table; ...@@ -158,12 +158,12 @@ htab_t type_hash_table;
static void build_real_from_int_cst_1 PARAMS ((PTR)); static void build_real_from_int_cst_1 PARAMS ((PTR));
static void set_type_quals PARAMS ((tree, int)); static void set_type_quals PARAMS ((tree, int));
static void append_random_chars PARAMS ((char *)); static void append_random_chars PARAMS ((char *));
static void mark_type_hash PARAMS ((void *));
static int type_hash_eq PARAMS ((const void*, const void*)); static int type_hash_eq PARAMS ((const void*, const void*));
static unsigned int type_hash_hash PARAMS ((const void*)); static unsigned int type_hash_hash PARAMS ((const void*));
static void print_type_hash_statistics PARAMS((void)); static void print_type_hash_statistics PARAMS((void));
static int mark_hash_entry PARAMS((void **, void *));
static void finish_vector_type PARAMS((tree)); static void finish_vector_type PARAMS((tree));
static int type_hash_marked_p PARAMS ((const void *));
static void type_hash_mark PARAMS ((const void *));
static int mark_tree_hashtable_entry PARAMS((void **, void *)); static int mark_tree_hashtable_entry PARAMS((void **, void *));
/* If non-null, these are language-specific helper functions for /* If non-null, these are language-specific helper functions for
...@@ -225,7 +225,8 @@ init_obstacks () ...@@ -225,7 +225,8 @@ init_obstacks ()
/* Initialize the hash table of types. */ /* Initialize the hash table of types. */
type_hash_table = htab_create (TYPE_HASH_INITIAL_SIZE, type_hash_hash, type_hash_table = htab_create (TYPE_HASH_INITIAL_SIZE, type_hash_hash,
type_hash_eq, 0); type_hash_eq, 0);
ggc_add_root (&type_hash_table, 1, sizeof type_hash_table, mark_type_hash); ggc_add_deletable_htab (type_hash_table, type_hash_marked_p,
type_hash_mark);
ggc_add_tree_root (global_trees, TI_MAX); ggc_add_tree_root (global_trees, TI_MAX);
ggc_add_tree_root (integer_types, itk_none); ggc_add_tree_root (integer_types, itk_none);
...@@ -3186,7 +3187,7 @@ type_hash_add (hashcode, type) ...@@ -3186,7 +3187,7 @@ type_hash_add (hashcode, type)
struct type_hash *h; struct type_hash *h;
void **loc; void **loc;
h = (struct type_hash *) permalloc (sizeof (struct type_hash)); h = (struct type_hash *) ggc_alloc (sizeof (struct type_hash));
h->hash = hashcode; h->hash = hashcode;
h->type = type; h->type = type;
loc = htab_find_slot_with_hash (type_hash_table, h, hashcode, INSERT); loc = htab_find_slot_with_hash (type_hash_table, h, hashcode, INSERT);
...@@ -3217,6 +3218,8 @@ type_hash_canon (hashcode, type) ...@@ -3217,6 +3218,8 @@ type_hash_canon (hashcode, type)
if (debug_no_type_hash) if (debug_no_type_hash)
return type; return type;
/* See if the type is in the hash table already. If so, return it.
Otherwise, add the type. */
t1 = type_hash_lookup (hashcode, type); t1 = type_hash_lookup (hashcode, type);
if (t1 != 0) if (t1 != 0)
{ {
...@@ -3226,37 +3229,29 @@ type_hash_canon (hashcode, type) ...@@ -3226,37 +3229,29 @@ type_hash_canon (hashcode, type)
#endif #endif
return t1; return t1;
} }
else
/* If this is a permanent type, record it for later reuse. */ {
type_hash_add (hashcode, type); type_hash_add (hashcode, type);
return type;
return type; }
} }
/* Callback function for htab_traverse. */ /* See if the data pointed to by the type hash table is marked. */
static int static int
mark_hash_entry (entry, param) type_hash_marked_p (p)
void **entry; const void *p;
void *param ATTRIBUTE_UNUSED;
{ {
struct type_hash *p = *(struct type_hash **) entry; return ggc_marked_p (((struct type_hash *) p)->type);
ggc_mark_tree (p->type);
/* Continue scan. */
return 1;
} }
/* Mark ARG (which is really a htab_t *) for GC. */ /* Mark the entry in the type hash table the type it points to is marked. */
static void static void
mark_type_hash (arg) type_hash_mark (p)
void *arg; const void *p;
{ {
htab_t t = *(htab_t *) arg; ggc_mark (p);
htab_traverse (t, mark_hash_entry, 0);
} }
/* Mark the hashtable slot pointed to by ENTRY (which is really a /* Mark the hashtable slot pointed to by ENTRY (which is really a
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment