2
0
mirror of git://gcc.gnu.org/git/gcc.git synced 2025-03-26 07:40:26 +08:00

Speed up walk_tree by introducing a special-purpose hash table.

* pointer-set.c: New file, special-purpose hash table.
	* pointer-set.h: New file.
	* tree.h (struct pointer_set_t): Declare as opaque type.
	(tree_walk): Last argument is pointer_set_t* now.
	* tree-inline.c (WALK_SUBTREE): Convert from htab to pset.
	(walk_type_fields):
	(walk_tree): Convert from htab_t to pointer_set_t for keeping
	track of which nodes have already been visited.
	(walk_tree_without_duplicates): Convert from htab_t to pointer_set_t.
	* cgraphunit.c (cgraph_create_edges): Likewise.
	(cgraph_characterize_statics_local): Likewise.
	* tree-dfa.c (collect_dfa_stats): Likewise.
	* langhooks-def.h (lhd_tree_inlining_walk_subtrees): Last arg is
	pointer_set_t* now.
	* langhooks.c (lhd_tree_inlining_walk_subtrees): Likewise.
	* langhooks.h (struct lang_hooks_for_tree_inlining): Last arg type
	of walk_subtrees is pointer_set_t* now.
	* Makefile.in (OBJS-common): add pointer-set.o
	(tree-inline.o): Depends on pointer-set.h
	(tree-dfa.o): Likewise
	(cgraphunit.o): Likewise
	* cp/Make-lang.in (pt.o): depends on pointer-set.h
	* cp/cp-tree.h (cp_walk_subtrees): Last argument is pointer_set_t* now.
	* cp/pt.c (struct pair_fn_data): Use pointer_set_t, not htab_t
	(for_each_template_parm): Convert from htab_t to pointer_set_t.
	* cp/tree.c (cp_walk_subtrees): Last argument is pointer_set_t* now.
	* java/lang.c (java_tree_inlining_walk_subtrees): Last arg is struct
	pointer_set_t* now.

From-SVN: r89062
This commit is contained in:
Matt Austern 2004-10-14 23:15:29 +00:00 committed by Matt Austern
parent 5d1b2a1e42
commit 0c58f841a5
18 changed files with 296 additions and 57 deletions

@ -1,3 +1,27 @@
2004-10-14 Matt Austern <austern@apple.com>
* pointer-set.c: New file, special-purpose hash table.
* pointer-set.h: New file.
* tree.h (struct pointer_set_t): Declare as opaque type.
(tree_walk): Last argument is pointer_set_t* now.
* tree-inline.c (WALK_SUBTREE): Convert from htab to pset.
(walk_type_fields):
(walk_tree): Convert from htab_t to pointer_set_t for keeping
track of which nodes have already been visited.
(walk_tree_without_duplicates): Convert from htab_t to pointer_set_t.
* cgraphunit.c (cgraph_create_edges): Likewise.
(cgraph_characterize_statics_local): Likewise.
* tree-dfa.c (collect_dfa_stats): Likewise.
* langhooks-def.h (lhd_tree_inlining_walk_subtrees): Last arg is
pointer_set_t* now.
* langhooks.c (lhd_tree_inlining_walk_subtrees): Likewise.
* langhooks.h (struct lang_hooks_for_tree_inlining): Last arg type
of walk_subtrees is pointer_set_t* now.
* Makefile.in (OBJS-common): add pointer-set.o
(tree-inline.o): Depends on pointer-set.h
(tree-dfa.o): Likewise
(cgraphunit.o): Likewise
2004-10-14 Geoffrey Keating <geoffk@apple.com>
* config/rs6000/darwin.h (ASM_SPEC): Delete.

@ -914,7 +914,7 @@ OBJS-common = \
params.o postreload.o postreload-gcse.o predict.o \
insn-preds.o integrate.o intl.o jump.o langhooks.o lcm.o lists.o \
local-alloc.o loop.o modulo-sched.o optabs.o options.o opts.o \
params.o postreload.o postreload-gcse.o predict.o \
params.o pointer-set.o postreload.o postreload-gcse.o predict.o \
print-rtl.o print-tree.o value-prof.o var-tracking.o \
profile.o ra.o ra-build.o ra-colorize.o ra-debug.o ra-rewrite.o \
real.o recog.o reg-stack.o regclass.o regmove.o regrename.o \
@ -1592,7 +1592,7 @@ tree-inline.o : tree-inline.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TREE_H) $(RTL_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h insn-config.h \
$(INTEGRATE_H) $(VARRAY_H) $(HASHTAB_H) $(SPLAY_TREE_H) toplev.h \
langhooks.h $(C_COMMON_H) tree-inline.h $(CGRAPH_H) intl.h function.h \
$(TREE_GIMPLE_H)
pointer-set.h $(TREE_GIMPLE_H)
print-tree.o : print-tree.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
$(GGC_H) langhooks.h real.h
stor-layout.o : stor-layout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
@ -1686,7 +1686,7 @@ tree-iterator.o : tree-iterator.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) \
coretypes.h $(GGC_H) tree-iterator.h tree-gimple.h gt-tree-iterator.h
tree-dfa.o : tree-dfa.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
$(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h diagnostic.h \
errors.h tree-inline.h $(HASHTAB_H) $(FLAGS_H) function.h $(TIMEVAR_H) \
errors.h tree-inline.h $(HASHTAB_H) pointer-set.h $(FLAGS_H) function.h $(TIMEVAR_H) \
convert.h $(TM_H) coretypes.h langhooks.h \
$(TREE_DUMP_H) tree-pass.h params.h $(CGRAPH_H)
tree-ssa-operands.o : tree-ssa-operands.c $(TREE_FLOW_H) $(CONFIG_H) \
@ -1923,7 +1923,7 @@ cgraph.o : cgraph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
output.h intl.h
cgraphunit.o : cgraphunit.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
langhooks.h tree-inline.h toplev.h $(FLAGS_H) $(GGC_H) $(TARGET_H) $(CGRAPH_H) intl.h \
function.h $(TREE_GIMPLE_H) $(TREE_FLOW_H)
pointer-set.h function.h $(TREE_GIMPLE_H) $(TREE_FLOW_H)
coverage.o : coverage.c gcov-io.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) $(RTL_H) $(TREE_H) $(FLAGS_H) output.h $(REGS_H) $(EXPR_H) function.h \
toplev.h $(GGC_H) $(TARGET_H) langhooks.h $(COVERAGE_H) libfuncs.h \
@ -2172,6 +2172,7 @@ lambda-code.o: lambda-code.c $(LAMBDA_H) $(GGC_H) $(SYSTEM_H) $(CONFIG_H) \
$(TREE_FLOW_H) $(TREE_DUMP_H) $(TIMEVAR_H) cfgloop.h \
$(TREE_DATA_REF_H) $(SCEV_H)
params.o : params.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(PARAMS_H) toplev.h
pointer-set.o: pointer-set.c pointer-set.h $(CONFIG_H) $(SYSTEM_H)
hooks.o: hooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(HOOKS_H)
pretty-print.o: $(CONFIG_H) $(SYSTEM_H) coretypes.h intl.h $(PRETTY_PRINT_H) \
$(TREE_H)

@ -186,7 +186,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "tree-flow.h"
#include "tree-inline.h"
#include "langhooks.h"
#include "hashtab.h"
#include "pointer-set.h"
#include "toplev.h"
#include "flags.h"
#include "ggc.h"
@ -223,7 +223,7 @@ static int overall_insns;
walk_tree_without_duplicates doesn't guarantee each node is visited
once because it gets a new htab upon each recursive call from
record_calls_1. */
static htab_t visited_nodes;
static struct pointer_set_t *visited_nodes;
static FILE *cgraph_dump_file;
@ -698,10 +698,9 @@ cgraph_create_edges (struct cgraph_node *node, tree body)
{
/* The nodes we're interested in are never shared, so walk
the tree ignoring duplicates. */
visited_nodes = htab_create (37, htab_hash_pointer,
htab_eq_pointer, NULL);
visited_nodes = pointer_set_create ();
walk_tree (&body, record_call_1, node, visited_nodes);
htab_delete (visited_nodes);
pointer_set_destroy (visited_nodes);
visited_nodes = NULL;
}
@ -2288,8 +2287,7 @@ cgraph_characterize_statics_local (struct cgraph_node *fn)
/* The nodes we're interested in are never shared, so walk
the tree ignoring duplicates. */
visited_nodes = htab_create (37, htab_hash_pointer,
htab_eq_pointer, NULL);
visited_nodes = pointer_set_create ();
/* FIXME -- PROFILE-RESTRUCTURE: Remove creation of _decl_uid vars. */
l->statics_read_by_decl_uid = BITMAP_GGC_ALLOC ();
@ -2299,7 +2297,7 @@ cgraph_characterize_statics_local (struct cgraph_node *fn)
fprintf (cgraph_dump_file, "\n local analysis of %s", cgraph_node_name (fn));
walk_tree (&DECL_SAVED_TREE (decl), scan_for_static_refs, fn, visited_nodes);
htab_delete (visited_nodes);
pointer_set_destroy (visited_nodes);
visited_nodes = NULL;
}

@ -1,3 +1,11 @@
2004-10-14 Matt Austern <austern@apple.com>
* Make-lang.in (pt.o): depends on pointer-set.h
* cp-tree.h (cp_walk_subtrees): Last argument is pointer_set_t* now.
* pt.c (struct pair_fn_data): Use pointer_set_t, not htab_t
(for_each_template_parm): Convert from htab_t to pointer_set_t.
* tree.c (cp_walk_subtrees): Last argument is pointer_set_t* now.
2004-10-13 Andrew Pinski <pinskia@physics.uc.edu>
PR c++/17661

@ -260,7 +260,7 @@ cp/except.o: cp/except.c $(CXX_TREE_H) $(TM_H) flags.h $(RTL_H) except.h toplev.
cp/expr.o: cp/expr.c $(CXX_TREE_H) $(TM_H) $(RTL_H) flags.h $(EXPR_H) toplev.h \
except.h $(TM_P_H)
cp/pt.o: cp/pt.c $(CXX_TREE_H) $(TM_H) cp/decl.h \
toplev.h $(RTL_H) except.h tree-inline.h gt-cp-pt.h
toplev.h $(RTL_H) except.h tree-inline.h pointer-set.h gt-cp-pt.h
cp/error.o: cp/error.c $(CXX_TREE_H) $(TM_H) toplev.h $(DIAGNOSTIC_H) \
flags.h real.h $(LANGHOOKS_DEF_H) $(CXX_PRETTY_PRINT_H)
cp/repo.o: cp/repo.c $(CXX_TREE_H) $(TM_H) toplev.h diagnostic.h \

@ -4215,7 +4215,7 @@ extern void verify_stmt_tree (tree);
extern tree find_tree (tree, tree);
extern linkage_kind decl_linkage (tree);
extern tree cp_walk_subtrees (tree*, int*, walk_tree_fn,
void*, void*);
void*, struct pointer_set_t*);
extern int cp_cannot_inline_tree_fn (tree*);
extern tree cp_add_pending_fn_decls (void*,tree);
extern int cp_is_overload_p (tree);

@ -32,6 +32,7 @@ Boston, MA 02111-1307, USA. */
#include "tm.h"
#include "obstack.h"
#include "tree.h"
#include "pointer-set.h"
#include "flags.h"
#include "cp-tree.h"
#include "tree-inline.h"
@ -113,7 +114,8 @@ static tree convert_nontype_argument (tree, tree);
static tree convert_template_argument (tree, tree, tree,
tsubst_flags_t, int, tree);
static tree get_bindings_overload (tree, tree, tree);
static int for_each_template_parm (tree, tree_fn_t, void*, htab_t);
static int for_each_template_parm (tree, tree_fn_t, void*,
struct pointer_set_t*);
static tree build_template_parm_index (int, int, int, tree, tree);
static int inline_needs_template_parms (tree);
static void push_inline_template_parms_recursive (tree, int);
@ -4683,7 +4685,7 @@ struct pair_fn_data
{
tree_fn_t fn;
void *data;
htab_t visited;
struct pointer_set_t *visited;
};
/* Called from for_each_template_parm via walk_tree. */
@ -4865,7 +4867,8 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
considered to be the function which always returns 1. */
static int
for_each_template_parm (tree t, tree_fn_t fn, void* data, htab_t visited)
for_each_template_parm (tree t, tree_fn_t fn, void* data,
struct pointer_set_t *visited)
{
struct pair_fn_data pfd;
int result;
@ -4882,8 +4885,7 @@ for_each_template_parm (tree t, tree_fn_t fn, void* data, htab_t visited)
if (visited)
pfd.visited = visited;
else
pfd.visited = htab_create (37, htab_hash_pointer, htab_eq_pointer,
NULL);
pfd.visited = pointer_set_create ();
result = walk_tree (&t,
for_each_template_parm_r,
&pfd,
@ -4891,7 +4893,10 @@ for_each_template_parm (tree t, tree_fn_t fn, void* data, htab_t visited)
/* Clean up. */
if (!visited)
htab_delete (pfd.visited);
{
pointer_set_destroy (pfd.visited);
pfd.visited = 0;
}
return result;
}

@ -1929,7 +1929,7 @@ cp_build_type_attribute_variant (tree type, tree attributes)
tree
cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
void *data, void *htab)
void *data, struct pointer_set_t *pset)
{
enum tree_code code = TREE_CODE (*tp);
location_t save_locus;
@ -1938,7 +1938,7 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
#define WALK_SUBTREE(NODE) \
do \
{ \
result = walk_tree (&(NODE), func, data, htab); \
result = walk_tree (&(NODE), func, data, pset); \
if (result) goto out; \
} \
while (0)

@ -1,3 +1,8 @@
2004-10-14 Matt Austern <austern@apple.com>
* lang.c (java_tree_inlining_walk_subtrees): Last arg is struct
pointer_set_t* now.
2004-10-13 Tom Tromey <tromey@redhat.com>
PR java/15578:

@ -58,7 +58,7 @@ static void put_decl_string (const char *, int);
static void put_decl_node (tree);
static void java_print_error_function (diagnostic_context *, const char *);
static tree java_tree_inlining_walk_subtrees (tree *, int *, walk_tree_fn,
void *, void *);
void *, struct pointer_set_t *);
static int merge_init_test_initialization (void * *, void *);
static int inline_init_test_initialization (void * *, void *);
static bool java_can_use_bit_fields_p (void);
@ -706,7 +706,7 @@ java_tree_inlining_walk_subtrees (tree *tp ATTRIBUTE_UNUSED,
int *subtrees ATTRIBUTE_UNUSED,
walk_tree_fn func ATTRIBUTE_UNUSED,
void *data ATTRIBUTE_UNUSED,
void *htab ATTRIBUTE_UNUSED)
struct pointer_set_t *pset ATTRIBUTE_UNUSED)
{
enum tree_code code;
tree result;
@ -714,7 +714,7 @@ java_tree_inlining_walk_subtrees (tree *tp ATTRIBUTE_UNUSED,
#define WALK_SUBTREE(NODE) \
do \
{ \
result = walk_tree (&(NODE), func, data, htab); \
result = walk_tree (&(NODE), func, data, pset); \
if (result) \
return result; \
} \

@ -73,7 +73,7 @@ extern size_t lhd_tree_size (enum tree_code);
/* Declarations of default tree inlining hooks. */
extern tree lhd_tree_inlining_walk_subtrees (tree *, int *, walk_tree_fn,
void *, void *);
void *, struct pointer_set_t*);
extern int lhd_tree_inlining_cannot_inline_tree_fn (tree *);
extern int lhd_tree_inlining_disregard_inline_limits (tree);
extern tree lhd_tree_inlining_add_pending_fn_decls (void *, tree);

@ -298,7 +298,7 @@ lhd_tree_inlining_walk_subtrees (tree *tp ATTRIBUTE_UNUSED,
int *subtrees ATTRIBUTE_UNUSED,
walk_tree_fn func ATTRIBUTE_UNUSED,
void *data ATTRIBUTE_UNUSED,
void *htab ATTRIBUTE_UNUSED)
struct pointer_set_t *pset ATTRIBUTE_UNUSED)
{
return NULL_TREE;
}

@ -35,7 +35,7 @@ struct lang_hooks_for_tree_inlining
{
tree (*walk_subtrees) (tree *, int *,
tree (*) (tree *, int *, void *),
void *, void *);
void *, struct pointer_set_t*);
int (*cannot_inline_tree_fn) (tree *);
int (*disregard_inline_limits) (tree);
tree (*add_pending_fn_decls) (void *, tree);

167
gcc/pointer-set.c Normal file

@ -0,0 +1,167 @@
/* Set operations on pointers
Copyright (C) 2004 Free Software Foundation, Inc.
This file is part of GCC.
GCC 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.
GCC 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 GCC; 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 "pointer-set.h"
/* A pointer sets is represented as a simple open-addressing hash
table. Simplifications: The hash code is based on the value of the
pointer, not what it points to. The number of buckets is always a
power of 2. Null pointers are a reserved value. Deletion is not
supported. There is no mechanism for user control of hash
function, equality comparison, initial size, or resizing policy.
*/
struct pointer_set_t
{
size_t log_slots;
size_t n_slots; /* n_slots = 2^log_slots */
size_t n_elements;
void **slots;
};
/* Use the multiplicative method, as described in Knuth 6.4, to obtain
a hash code for P in the range [0, MAX). MAX == 2^LOGMAX.
Summary of this method: Multiply p by some number A that's
relatively prime to 2^sizeof(size_t). The result is two words.
Discard the most significant word, and return the most significant
N bits of the least significant word. As suggested by Knuth, our
choice for A is the integer part of 2^32 / phi, where phi is the
golden ratio.
We don't need to do anything special for full-width multiplication
because we're only interested in the least significant word of the
product, and unsigned arithmetic in C is modulo the word size. */
static inline size_t
hash1 (const void *p, unsigned long max, unsigned long logmax)
{
const unsigned long A = 0x9e3779b9u;
const unsigned long shift = sizeof(unsigned long) * CHAR_BIT - logmax;
return ((A * (unsigned long) p) >> shift) & (max - 1);
}
/* Allocate an empty pointer set. */
struct pointer_set_t *
pointer_set_create (void)
{
struct pointer_set_t *result = XNEW (struct pointer_set_t);
result->n_elements = 0;
result->log_slots = 8;
result->n_slots = (size_t) 1 << result->log_slots;
result->slots = XCNEWVEC (void *, result->n_slots);
return result;
}
/* Reclaims all memory associated with PSET. */
void pointer_set_destroy (struct pointer_set_t *pset)
{
XDELETEVEC (pset->slots);
XDELETE (pset);
}
/* Returns nonzero if PSET contains P. P must be nonnull.
Collisions are resolved by linear probing. More complicated
collision management schemes are only useful when the load factor
significatly exceeds 0.5, and we never let that happen. */
int
pointer_set_contains (struct pointer_set_t *pset, void *p)
{
size_t n = hash1 (p, pset->n_slots, pset->log_slots);
while (true)
{
if (pset->slots[n] == p)
return 1;
else if (pset->slots[n] == 0)
return 0;
else
{
++n;
if (n == pset->n_slots)
n = 0;
}
}
}
/* Subroutine of pointer_set_insert. Inserts P into an empty
element of SLOTS, an array of length N_SLOTS. Returns nonzero
if P was already present in N_SLOTS. */
static int
insert_aux (void *p, void **slots, size_t n_slots, size_t log_slots)
{
size_t n = hash1 (p, n_slots, log_slots);
while (true)
{
if (slots[n] == p)
return 1;
else if (slots[n] == 0)
{
slots[n] = p;
return 0;
}
else
{
++n;
if (n == n_slots)
n = 0;
}
}
}
/* Inserts P into PSET if it wasn't already there. Returns nonzero
if it was already there. P must be nonnull. */
int
pointer_set_insert (struct pointer_set_t *pset, void *p)
{
if (insert_aux (p, pset->slots, pset->n_slots, pset->log_slots))
return 1;
/* We've inserted a new element. Expand the table if necessary to keep
the load factor small. */
++pset->n_elements;
if (pset->n_elements > pset->n_slots / 4)
{
size_t new_log_slots = pset->log_slots + 1;
size_t new_n_slots = pset->n_slots * 2;
void **new_slots = XCNEWVEC (void *, new_n_slots);
size_t i;
for (i = 0; i < pset->n_slots; ++i)
{
if (pset->slots[i])
insert_aux (pset->slots[i], new_slots, new_n_slots, new_log_slots);
}
XDELETEVEC (pset->slots);
pset->n_slots = new_n_slots;
pset->log_slots = new_log_slots;
pset->slots = new_slots;
}
return 0;
}

32
gcc/pointer-set.h Normal file

@ -0,0 +1,32 @@
/* Set operations on pointers
Copyright (C) 2004 Free Software Foundation, Inc.
This file is part of GCC.
GCC 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.
GCC 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 GCC; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
#ifndef POINTER_SET_H
#define POINTER_SET_H
struct pointer_set_t;
struct pointer_set_t *pointer_set_create (void);
void pointer_set_destroy (struct pointer_set_t *pset);
int pointer_set_contains (struct pointer_set_t *pset, void *p);
int pointer_set_insert (struct pointer_set_t *pset, void *p);
#endif /* POINTER_SET_H */

@ -24,6 +24,7 @@ Boston, MA 02111-1307, USA. */
#include "coretypes.h"
#include "tm.h"
#include "hashtab.h"
#include "pointer-set.h"
#include "tree.h"
#include "rtl.h"
#include "tm_p.h"
@ -759,7 +760,7 @@ debug_dfa_stats (void)
static void
collect_dfa_stats (struct dfa_stats_d *dfa_stats_p)
{
htab_t htab;
struct pointer_set_t *pset;
basic_block bb;
block_stmt_iterator i;
@ -769,13 +770,13 @@ collect_dfa_stats (struct dfa_stats_d *dfa_stats_p)
/* Walk all the trees in the function counting references. Start at
basic block 0, but don't stop at block boundaries. */
htab = htab_create (30, htab_hash_pointer, htab_eq_pointer, NULL);
pset = pointer_set_create ();
for (i = bsi_start (BASIC_BLOCK (0)); !bsi_end_p (i); bsi_next (&i))
walk_tree (bsi_stmt_ptr (i), collect_dfa_stats_r, (void *) dfa_stats_p,
(void *) htab);
pset);
htab_delete (htab);
pointer_set_destroy (pset);
FOR_EACH_BB (bb)
{

@ -35,6 +35,7 @@ Boston, MA 02111-1307, USA. */
#include "integrate.h"
#include "varray.h"
#include "hashtab.h"
#include "pointer-set.h"
#include "splay-tree.h"
#include "langhooks.h"
#include "cgraph.h"
@ -1877,7 +1878,7 @@ save_body (tree fn, tree *arg_copy, tree *sc_copy)
#define WALK_SUBTREE(NODE) \
do \
{ \
result = walk_tree (&(NODE), func, data, htab); \
result = walk_tree (&(NODE), func, data, pset); \
if (result) \
return result; \
} \
@ -1888,7 +1889,8 @@ save_body (tree fn, tree *arg_copy, tree *sc_copy)
value are as for walk_tree. */
static tree
walk_type_fields (tree type, walk_tree_fn func, void *data, void *htab)
walk_type_fields (tree type, walk_tree_fn func, void *data,
struct pointer_set_t *pset)
{
tree result = NULL_TREE;
@ -1906,7 +1908,7 @@ walk_type_fields (tree type, walk_tree_fn func, void *data, void *htab)
if (POINTER_TYPE_P (TREE_TYPE (type))
&& POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (type)))
&& POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (TREE_TYPE (type))))
&& !htab)
&& !pset)
{
result = walk_tree_without_duplicates (&TREE_TYPE (type),
func, data);
@ -1971,13 +1973,12 @@ walk_type_fields (tree type, walk_tree_fn func, void *data, void *htab)
/* Apply FUNC to all the sub-trees of TP in a pre-order traversal. FUNC is
called with the DATA and the address of each sub-tree. If FUNC returns a
non-NULL value, the traversal is aborted, and the value returned by FUNC
is returned. If HTAB is non-NULL it is used to record the nodes visited,
is returned. If PSET is non-NULL it is used to record the nodes visited,
and to avoid visiting a node more than once. */
tree
walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_)
walk_tree (tree *tp, walk_tree_fn func, void *data, struct pointer_set_t *pset)
{
htab_t htab = (htab_t) htab_;
enum tree_code code;
int walk_subtrees;
tree result;
@ -1995,17 +1996,10 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_)
if (!*tp)
return NULL_TREE;
if (htab)
{
void **slot;
/* Don't walk the same tree twice, if the user has requested
that we avoid doing so. */
slot = htab_find_slot (htab, *tp, INSERT);
if (*slot)
return NULL_TREE;
*slot = *tp;
}
/* Don't walk the same tree twice, if the user has requested
that we avoid doing so. */
if (pset && pointer_set_insert (pset, *tp))
return NULL_TREE;
/* Call the function. */
walk_subtrees = 1;
@ -2029,7 +2023,7 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_)
}
result = lang_hooks.tree_inlining.walk_subtrees (tp, &walk_subtrees, func,
data, htab);
data, pset);
if (result || ! walk_subtrees)
return result;
@ -2053,7 +2047,7 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_)
if (result || !walk_subtrees)
return NULL_TREE;
result = walk_type_fields (*type_p, func, data, htab_);
result = walk_type_fields (*type_p, func, data, pset);
if (result)
return result;
@ -2124,7 +2118,7 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_)
/* If this is a type, walk the needed fields in the type. */
else if (TYPE_P (*tp))
{
result = walk_type_fields (*tp, func, data, htab_);
result = walk_type_fields (*tp, func, data, pset);
if (result)
return result;
}
@ -2227,11 +2221,11 @@ tree
walk_tree_without_duplicates (tree *tp, walk_tree_fn func, void *data)
{
tree result;
htab_t htab;
struct pointer_set_t *pset;
htab = htab_create (37, htab_hash_pointer, htab_eq_pointer, NULL);
result = walk_tree (tp, func, data, htab);
htab_delete (htab);
pset = pointer_set_create ();
result = walk_tree (tp, func, data, pset);
pointer_set_destroy (pset);
return result;
}

@ -3790,10 +3790,14 @@ extern void dwarf2out_return_reg (const char *, unsigned);
/* In tree-inline.c */
/* The type of a set of already-visited pointers. Functions for creating
and manipulating it are declared in pointer-set.h */
struct pointer_set_t;
/* The type of a callback function for walking over tree structure. */
typedef tree (*walk_tree_fn) (tree *, int *, void *);
extern tree walk_tree (tree*, walk_tree_fn, void*, void*);
extern tree walk_tree (tree*, walk_tree_fn, void*, struct pointer_set_t*);
extern tree walk_tree_without_duplicates (tree*, walk_tree_fn, void*);
/* In tree-dump.c */