mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-08 17:37:43 +08:00
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
This commit is contained in:
parent
c762ab6ebb
commit
4c160717ca
@ -1,3 +1,26 @@
|
||||
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>
|
||||
|
||||
* sh.c (shiftcosts): Don't use shiftcosts array for modes wider
|
||||
|
@ -1310,7 +1310,7 @@ dumpvers: dumpvers.c
|
||||
version.o: version.c version.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_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 \
|
||||
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 \
|
||||
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 \
|
||||
$(EXPR_H) $(RTL_H) $(GGC_H) $(TM_P_H)
|
||||
fold-const.o : fold-const.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) flags.h \
|
||||
toplev.h $(HASHTAB_H) $(EXPR_H) $(RTL_H) $(GGC_H) $(TM_P_H)
|
||||
diagnostic.o : diagnostic.c diagnostic.h real.h diagnostic.def \
|
||||
$(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(TM_P_H) flags.h $(GGC_H) \
|
||||
input.h toplev.h intl.h
|
||||
|
128
gcc/fold-const.c
128
gcc/fold-const.c
@ -51,6 +51,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
#include "tm_p.h"
|
||||
#include "toplev.h"
|
||||
#include "ggc.h"
|
||||
#include "hashtab.h"
|
||||
|
||||
static void encode PARAMS ((HOST_WIDE_INT *,
|
||||
unsigned HOST_WIDE_INT,
|
||||
@ -65,9 +66,11 @@ static tree negate_expr PARAMS ((tree));
|
||||
static tree split_tree PARAMS ((tree, enum tree_code, tree *, tree *,
|
||||
int));
|
||||
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 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 tree fold_convert PARAMS ((tree, tree));
|
||||
static enum tree_code invert_tree_comparison PARAMS ((enum tree_code));
|
||||
@ -1478,14 +1481,13 @@ associate_trees (t1, t2, code, type)
|
||||
/* Combine two integer constants ARG1 and ARG2 under operation CODE
|
||||
to produce a new constant.
|
||||
|
||||
If NOTRUNC is nonzero, do not truncate the result to fit the data type.
|
||||
If FORSIZE is nonzero, compute overflow for unsigned types. */
|
||||
If NOTRUNC is nonzero, do not truncate the result to fit the data type. */
|
||||
|
||||
static tree
|
||||
int_const_binop (code, arg1, arg2, notrunc, forsize)
|
||||
int_const_binop (code, arg1, arg2, notrunc)
|
||||
enum tree_code code;
|
||||
register tree arg1, arg2;
|
||||
int notrunc, forsize;
|
||||
int notrunc;
|
||||
{
|
||||
unsigned HOST_WIDE_INT int1l, int2l;
|
||||
HOST_WIDE_INT int1h, int2h;
|
||||
@ -1494,7 +1496,10 @@ int_const_binop (code, arg1, arg2, notrunc, forsize)
|
||||
unsigned HOST_WIDE_INT garbagel;
|
||||
HOST_WIDE_INT garbageh;
|
||||
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 no_overflow = 0;
|
||||
|
||||
@ -1527,7 +1532,7 @@ int_const_binop (code, arg1, arg2, notrunc, forsize)
|
||||
/* It's unclear from the C standard whether shifts can overflow.
|
||||
The following code ignores overflow; perhaps a C standard
|
||||
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);
|
||||
no_overflow = 1;
|
||||
break;
|
||||
@ -1535,7 +1540,7 @@ int_const_binop (code, arg1, arg2, notrunc, forsize)
|
||||
case RROTATE_EXPR:
|
||||
int2l = - int2l;
|
||||
case LROTATE_EXPR:
|
||||
lrotate_double (int1l, int1h, int2l, TYPE_PRECISION (TREE_TYPE (arg1)),
|
||||
lrotate_double (int1l, int1h, int2l, TYPE_PRECISION (type),
|
||||
&low, &hi);
|
||||
break;
|
||||
|
||||
@ -1583,8 +1588,7 @@ int_const_binop (code, arg1, arg2, notrunc, forsize)
|
||||
low = 1, hi = 0;
|
||||
break;
|
||||
}
|
||||
overflow = div_and_round_double (code, uns,
|
||||
int1l, int1h, int2l, int2h,
|
||||
overflow = div_and_round_double (code, uns, int1l, int1h, int2l, int2h,
|
||||
&low, &hi, &garbagel, &garbageh);
|
||||
break;
|
||||
|
||||
@ -1632,9 +1636,14 @@ int_const_binop (code, arg1, arg2, notrunc, forsize)
|
||||
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))
|
||||
return size_int_type_wide (low, TREE_TYPE (arg1));
|
||||
return size_int_type_wide (low, type);
|
||||
else
|
||||
{
|
||||
t = build_int_2 (low, hi);
|
||||
@ -1642,14 +1651,16 @@ int_const_binop (code, arg1, arg2, notrunc, forsize)
|
||||
}
|
||||
|
||||
TREE_OVERFLOW (t)
|
||||
= ((notrunc ? (!uns || forsize) && overflow
|
||||
: force_fit_type (t, (!uns || forsize) && overflow) && ! no_overflow)
|
||||
= ((notrunc
|
||||
? (!uns || is_sizetype) && overflow
|
||||
: (force_fit_type (t, (!uns || is_sizetype) && overflow)
|
||||
&& ! no_overflow))
|
||||
| TREE_OVERFLOW (arg1)
|
||||
| TREE_OVERFLOW (arg2));
|
||||
|
||||
/* If we're doing a size calculation, unsigned arithmetic does overflow.
|
||||
So check if force_fit_type truncated the value. */
|
||||
if (forsize
|
||||
if (is_sizetype
|
||||
&& ! TREE_OVERFLOW (t)
|
||||
&& (TREE_INT_CST_HIGH (t) != hi
|
||||
|| TREE_INT_CST_LOW (t) != low))
|
||||
@ -1740,7 +1751,7 @@ const_binop (code, arg1, arg2, notrunc)
|
||||
STRIP_NOPS (arg2);
|
||||
|
||||
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 (TREE_CODE (arg1) == REAL_CST)
|
||||
@ -1865,6 +1876,39 @@ const_binop (code, arg1, arg2, notrunc)
|
||||
}
|
||||
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
|
||||
bits are given by NUMBER and of the sizetype represented by KIND. */
|
||||
@ -1884,40 +1928,38 @@ size_int_type_wide (number, type)
|
||||
HOST_WIDE_INT number;
|
||||
tree type;
|
||||
{
|
||||
/* Type-size nodes already made for small sizes. */
|
||||
static tree size_table[2048 + 1];
|
||||
static int init_p = 0;
|
||||
tree t;
|
||||
static htab_t size_htab = 0;
|
||||
static tree new_const = 0;
|
||||
PTR *slot;
|
||||
|
||||
if (! init_p)
|
||||
if (size_htab == 0)
|
||||
{
|
||||
ggc_add_tree_root ((tree *) size_table,
|
||||
sizeof size_table / sizeof (tree));
|
||||
init_p = 1;
|
||||
size_htab = htab_create (1024, size_htab_hash, size_htab_eq, NULL);
|
||||
ggc_add_deletable_htab (size_htab, NULL, NULL);
|
||||
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
|
||||
cached entries, see if it is already in the table and put it there
|
||||
if not. */
|
||||
if (number >= 0 && number < (int) ARRAY_SIZE (size_table))
|
||||
/* Adjust NEW_CONST to be the constant we want. If it's already in the
|
||||
hash table, we return the value from the hash table. Otherwise, we
|
||||
place that in the hash table and make a new node for the next time. */
|
||||
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)
|
||||
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;
|
||||
tree t = new_const;
|
||||
|
||||
*slot = (PTR) new_const;
|
||||
new_const = make_node (INTEGER_CST);
|
||||
return t;
|
||||
}
|
||||
|
||||
t = build_int_2 (number, number < 0 ? -1 : 0);
|
||||
TREE_TYPE (t) = type;
|
||||
TREE_OVERFLOW (t) = TREE_CONSTANT_OVERFLOW (t) = force_fit_type (t, 0);
|
||||
return t;
|
||||
else
|
||||
return (tree) *slot;
|
||||
}
|
||||
|
||||
/* Combine operands OP1 and OP2 with arithmetic operation CODE. CODE
|
||||
@ -1949,7 +1991,7 @@ size_binop (code, arg0, arg1)
|
||||
return arg1;
|
||||
|
||||
/* 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)
|
||||
|
@ -27,6 +27,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
#include "tree.h"
|
||||
#include "tm_p.h"
|
||||
#include "hash.h"
|
||||
#include "hashtab.h"
|
||||
#include "varray.h"
|
||||
#include "ggc.h"
|
||||
|
||||
@ -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_tree_varray_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 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. */
|
||||
|
||||
@ -166,12 +168,79 @@ ggc_del_root (base)
|
||||
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. */
|
||||
|
||||
void
|
||||
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");
|
||||
|
||||
@ -189,6 +258,16 @@ ggc_mark_roots ()
|
||||
/* Mark all the queued up trees, and their children. */
|
||||
ggc_mark_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
|
||||
@ -463,7 +542,7 @@ ggc_mark_tree_varray (v)
|
||||
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
|
||||
ggc_mark_tree_hash_table_entry (he, k)
|
||||
|
@ -1001,6 +1001,35 @@ ggc_set_mark (p)
|
||||
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. */
|
||||
|
||||
size_t
|
||||
|
@ -228,6 +228,23 @@ ggc_set_mark (p)
|
||||
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. */
|
||||
|
||||
size_t
|
||||
|
88
gcc/ggc.h
88
gcc/ggc.h
@ -47,23 +47,39 @@ extern const char digit_vector[]; /* "0" .. "9" */
|
||||
extern varray_type ggc_pending_trees;
|
||||
|
||||
/* Manipulate global roots that are needed between calls to gc. */
|
||||
void ggc_add_root PARAMS ((void *base, int nelt, int size, void (*)(void *)));
|
||||
void ggc_add_rtx_root PARAMS ((struct rtx_def **, int nelt));
|
||||
void ggc_add_tree_root PARAMS ((union tree_node **, int nelt));
|
||||
void ggc_add_rtx_varray_root PARAMS ((struct varray_head_tag **, int nelt));
|
||||
void ggc_add_tree_varray_root PARAMS ((struct varray_head_tag **, int nelt));
|
||||
void ggc_add_tree_hash_table_root PARAMS ((struct hash_table **, int nelt));
|
||||
void ggc_del_root PARAMS ((void *base));
|
||||
extern void ggc_add_root PARAMS ((void *base, int nelt,
|
||||
int size, void (*)(void *)));
|
||||
extern void ggc_add_rtx_root PARAMS ((struct rtx_def **, int nelt));
|
||||
extern void ggc_add_tree_root PARAMS ((union tree_node **,
|
||||
int nelt));
|
||||
extern void ggc_add_rtx_varray_root PARAMS ((struct varray_head_tag **,
|
||||
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
|
||||
pointers to mark other objects too. */
|
||||
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_hash_table PARAMS ((struct hash_table *));
|
||||
extern void ggc_mark_roots PARAMS ((void));
|
||||
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_hash_table PARAMS ((struct hash_table *));
|
||||
extern void ggc_mark_roots PARAMS ((void));
|
||||
|
||||
extern void ggc_mark_rtx_children PARAMS ((struct rtx_def *));
|
||||
extern void ggc_mark_rtvec_children PARAMS ((struct rtvec_def *));
|
||||
extern void ggc_mark_rtx_children PARAMS ((struct rtx_def *));
|
||||
extern void ggc_mark_rtvec_children PARAMS ((struct rtvec_def *));
|
||||
|
||||
/* If EXPR is not NULL and previously unmarked, mark it and evaluate
|
||||
to true. Otherwise evaluate to false. */
|
||||
@ -108,23 +124,23 @@ extern void ggc_mark_rtvec_children PARAMS ((struct rtvec_def *));
|
||||
/* A GC implementation must provide these functions. */
|
||||
|
||||
/* Initialize the garbage collector. */
|
||||
extern void init_ggc PARAMS ((void));
|
||||
extern void init_stringpool PARAMS ((void));
|
||||
extern void init_ggc PARAMS ((void));
|
||||
extern void init_stringpool PARAMS ((void));
|
||||
|
||||
/* Start a new GGC context. Memory allocated in previous contexts
|
||||
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
|
||||
will be merged with the old context. */
|
||||
extern void ggc_pop_context PARAMS ((void));
|
||||
extern void ggc_pop_context PARAMS ((void));
|
||||
|
||||
/* Allocation. */
|
||||
|
||||
/* The internal primitive. */
|
||||
void *ggc_alloc PARAMS ((size_t));
|
||||
extern void *ggc_alloc PARAMS ((size_t));
|
||||
/* 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) \
|
||||
((struct rtx_def *) ggc_alloc (sizeof (struct rtx_def) \
|
||||
@ -139,27 +155,33 @@ void *ggc_alloc_cleared PARAMS ((size_t));
|
||||
/* Allocate a gc-able string, and fill it with LENGTH bytes from CONTENTS.
|
||||
If LENGTH is -1, then CONTENTS is assumed to be a
|
||||
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. */
|
||||
#define ggc_strdup(S) ggc_alloc_string((S), -1)
|
||||
|
||||
/* Invoke the collector. Garbage collection occurs only when this
|
||||
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
|
||||
follow pointers. This function is called by ggc_mark_*. It
|
||||
returns zero if the object was not previously marked; non-zero if
|
||||
the object was already marked, or if, for any other reason,
|
||||
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. */
|
||||
|
||||
/* This is the language's opportunity to mark nodes held through
|
||||
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
|
||||
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 *));
|
||||
|
||||
/* Mark functions for various structs scattered about. */
|
||||
|
||||
void mark_eh_status PARAMS ((struct eh_status *));
|
||||
void mark_emit_status PARAMS ((struct emit_status *));
|
||||
void mark_expr_status PARAMS ((struct expr_status *));
|
||||
void mark_stmt_status PARAMS ((struct stmt_status *));
|
||||
void mark_varasm_status PARAMS ((struct varasm_status *));
|
||||
void mark_optab PARAMS ((void *));
|
||||
void mark_eh_status PARAMS ((struct eh_status *));
|
||||
void mark_emit_status PARAMS ((struct emit_status *));
|
||||
void mark_expr_status PARAMS ((struct expr_status *));
|
||||
void mark_stmt_status PARAMS ((struct stmt_status *));
|
||||
void mark_varasm_status PARAMS ((struct varasm_status *));
|
||||
void mark_optab PARAMS ((void *));
|
||||
|
||||
/* Statistics. */
|
||||
|
||||
@ -203,12 +225,12 @@ typedef struct ggc_statistics
|
||||
} ggc_statistics;
|
||||
|
||||
/* 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
|
||||
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. */
|
||||
extern void ggc_print_statistics PARAMS ((void));
|
||||
void stringpool_statistics PARAMS ((void));
|
||||
extern void ggc_print_statistics PARAMS ((void));
|
||||
extern void stringpool_statistics PARAMS ((void));
|
||||
|
45
gcc/tree.c
45
gcc/tree.c
@ -158,12 +158,12 @@ htab_t type_hash_table;
|
||||
static void build_real_from_int_cst_1 PARAMS ((PTR));
|
||||
static void set_type_quals PARAMS ((tree, int));
|
||||
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 unsigned int type_hash_hash PARAMS ((const 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 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 *));
|
||||
|
||||
/* If non-null, these are language-specific helper functions for
|
||||
@ -225,7 +225,8 @@ init_obstacks ()
|
||||
/* Initialize the hash table of types. */
|
||||
type_hash_table = htab_create (TYPE_HASH_INITIAL_SIZE, type_hash_hash,
|
||||
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 (integer_types, itk_none);
|
||||
|
||||
@ -3186,7 +3187,7 @@ type_hash_add (hashcode, type)
|
||||
struct type_hash *h;
|
||||
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->type = type;
|
||||
loc = htab_find_slot_with_hash (type_hash_table, h, hashcode, INSERT);
|
||||
@ -3217,6 +3218,8 @@ type_hash_canon (hashcode, type)
|
||||
if (debug_no_type_hash)
|
||||
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);
|
||||
if (t1 != 0)
|
||||
{
|
||||
@ -3226,37 +3229,29 @@ type_hash_canon (hashcode, type)
|
||||
#endif
|
||||
return t1;
|
||||
}
|
||||
|
||||
/* If this is a permanent type, record it for later reuse. */
|
||||
type_hash_add (hashcode, type);
|
||||
|
||||
return type;
|
||||
else
|
||||
{
|
||||
type_hash_add (hashcode, type);
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
/* Callback function for htab_traverse. */
|
||||
/* See if the data pointed to by the type hash table is marked. */
|
||||
|
||||
static int
|
||||
mark_hash_entry (entry, param)
|
||||
void **entry;
|
||||
void *param ATTRIBUTE_UNUSED;
|
||||
type_hash_marked_p (p)
|
||||
const void *p;
|
||||
{
|
||||
struct type_hash *p = *(struct type_hash **) entry;
|
||||
|
||||
ggc_mark_tree (p->type);
|
||||
|
||||
/* Continue scan. */
|
||||
return 1;
|
||||
return ggc_marked_p (((struct type_hash *) p)->type);
|
||||
}
|
||||
|
||||
/* 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
|
||||
mark_type_hash (arg)
|
||||
void *arg;
|
||||
type_hash_mark (p)
|
||||
const void *p;
|
||||
{
|
||||
htab_t t = *(htab_t *) arg;
|
||||
|
||||
htab_traverse (t, mark_hash_entry, 0);
|
||||
ggc_mark (p);
|
||||
}
|
||||
|
||||
/* Mark the hashtable slot pointed to by ENTRY (which is really a
|
||||
|
Loading…
Reference in New Issue
Block a user