lto.c (hash_canonical_type): Split out from ...

2013-10-15  Richard Biener  <rguenther@suse.de>

	lto/
	* lto.c (hash_canonical_type): Split out from ...
	(iterative_hash_canonical_type): ... here.  Register types
	we recurse to.
	(gimple_canonical_type_hash): Adjust.
	(gimple_register_canonical_type_1): Split out from ...
	(gimple_register_canonical_type): ... here.  Cache computed
	hash value.
	(lto_register_canonical_types): Split into two modes,
	clearing and computing TYPE_CANONICAL.
	(lto_read_decls): Adjust.
	(read_cgraph_and_symbols): Do two passes over global trees,
	first clearing then computing TYPE_CANONICAL.

From-SVN: r203600
This commit is contained in:
Richard Biener 2013-10-15 11:13:04 +00:00 committed by Richard Biener
parent 7569f6972e
commit fffda8d7a3
2 changed files with 107 additions and 49 deletions

View File

@ -1,3 +1,18 @@
2013-10-15 Richard Biener <rguenther@suse.de>
* lto.c (hash_canonical_type): Split out from ...
(iterative_hash_canonical_type): ... here. Register types
we recurse to.
(gimple_canonical_type_hash): Adjust.
(gimple_register_canonical_type_1): Split out from ...
(gimple_register_canonical_type): ... here. Cache computed
hash value.
(lto_register_canonical_types): Split into two modes,
clearing and computing TYPE_CANONICAL.
(lto_read_decls): Adjust.
(read_cgraph_and_symbols): Do two passes over global trees,
first clearing then computing TYPE_CANONICAL.
2013-10-14 Richard Biener <rguenther@suse.de> 2013-10-14 Richard Biener <rguenther@suse.de>
* lto.c (gimple_canonical_types): Move out-of GC space. * lto.c (gimple_canonical_types): Move out-of GC space.

View File

@ -260,21 +260,19 @@ static pointer_map <hashval_t> *canonical_type_hash_cache;
static unsigned long num_canonical_type_hash_entries; static unsigned long num_canonical_type_hash_entries;
static unsigned long num_canonical_type_hash_queries; static unsigned long num_canonical_type_hash_queries;
/* Returning a hash value for gimple type TYPE combined with VAL. static hashval_t iterative_hash_canonical_type (tree type, hashval_t val);
static hashval_t gimple_canonical_type_hash (const void *p);
static void gimple_register_canonical_type_1 (tree t, hashval_t hash);
/* Returning a hash value for gimple type TYPE.
The hash value returned is equal for types considered compatible The hash value returned is equal for types considered compatible
by gimple_canonical_types_compatible_p. */ by gimple_canonical_types_compatible_p. */
static hashval_t static hashval_t
iterative_hash_canonical_type (tree type, hashval_t val) hash_canonical_type (tree type)
{ {
hashval_t v; hashval_t v;
hashval_t *slot;
num_canonical_type_hash_queries++;
slot = canonical_type_hash_cache->contains (type);
if (slot)
return iterative_hash_hashval_t (*slot, val);
/* Combine a few common features of types so that types are grouped into /* Combine a few common features of types so that types are grouped into
smaller sets; when searching for existing matching types to merge, smaller sets; when searching for existing matching types to merge,
@ -373,18 +371,43 @@ iterative_hash_canonical_type (tree type, hashval_t val)
v = iterative_hash_hashval_t (nf, v); v = iterative_hash_hashval_t (nf, v);
} }
/* Cache the just computed hash value. */ return v;
num_canonical_type_hash_entries++; }
slot = canonical_type_hash_cache->insert (type);
*slot = v;
/* Returning a hash value for gimple type TYPE combined with VAL. */
static hashval_t
iterative_hash_canonical_type (tree type, hashval_t val)
{
hashval_t v;
/* An already processed type. */
if (TYPE_CANONICAL (type))
{
type = TYPE_CANONICAL (type);
v = gimple_canonical_type_hash (type);
}
else
{
/* Canonical types should not be able to form SCCs by design, this
recursion is just because we do not register canonical types in
optimal order. To avoid quadratic behavior also register the
type here. */
v = hash_canonical_type (type);
gimple_register_canonical_type_1 (type, v);
}
return iterative_hash_hashval_t (v, val); return iterative_hash_hashval_t (v, val);
} }
/* Returns the hash for a canonical type P. */
static hashval_t static hashval_t
gimple_canonical_type_hash (const void *p) gimple_canonical_type_hash (const void *p)
{ {
return iterative_hash_canonical_type (CONST_CAST_TREE ((const_tree) p), 0); num_canonical_type_hash_queries++;
hashval_t *slot
= canonical_type_hash_cache->contains (CONST_CAST_TREE ((const_tree) p));
gcc_assert (slot != NULL);
return *slot;
} }
@ -614,60 +637,73 @@ gimple_canonical_type_eq (const void *p1, const void *p2)
CONST_CAST_TREE (t2)); CONST_CAST_TREE (t2));
} }
/* Register type T in the global type table gimple_types. /* Main worker for gimple_register_canonical_type. */
If another type T', compatible with T, already existed in
gimple_types then return T', otherwise return T. This is used by static void
LTO to merge identical types read from different TUs. gimple_register_canonical_type_1 (tree t, hashval_t hash)
{
void **slot;
gcc_checking_assert (TYPE_P (t) && !TYPE_CANONICAL (t));
slot = htab_find_slot_with_hash (gimple_canonical_types, t, hash, INSERT);
if (*slot)
{
tree new_type = (tree)(*slot);
gcc_checking_assert (new_type != t);
TYPE_CANONICAL (t) = new_type;
}
else
{
TYPE_CANONICAL (t) = t;
*slot = (void *) t;
/* Cache the just computed hash value. */
num_canonical_type_hash_entries++;
bool existed_p;
hashval_t *hslot = canonical_type_hash_cache->insert (t, &existed_p);
gcc_assert (!existed_p);
*hslot = hash;
}
}
/* Register type T in the global type table gimple_types and set
TYPE_CANONICAL of T accordingly.
This is used by LTO to merge structurally equivalent types for
type-based aliasing purposes across different TUs and languages.
??? This merging does not exactly match how the tree.c middle-end ??? This merging does not exactly match how the tree.c middle-end
functions will assign TYPE_CANONICAL when new types are created functions will assign TYPE_CANONICAL when new types are created
during optimization (which at least happens for pointer and array during optimization (which at least happens for pointer and array
types). */ types). */
static tree static void
gimple_register_canonical_type (tree t) gimple_register_canonical_type (tree t)
{ {
void **slot;
gcc_assert (TYPE_P (t));
if (TYPE_CANONICAL (t)) if (TYPE_CANONICAL (t))
return TYPE_CANONICAL (t); return;
slot = htab_find_slot (gimple_canonical_types, t, INSERT); gimple_register_canonical_type_1 (t, hash_canonical_type (t));
if (*slot
&& *(tree *)slot != t)
{
tree new_type = (tree) *((tree *) slot);
TYPE_CANONICAL (t) = new_type;
t = new_type;
}
else
{
TYPE_CANONICAL (t) = t;
*slot = (void *) t;
}
return t;
} }
/* Re-compute TYPE_CANONICAL for NODE and related types. */ /* Re-compute TYPE_CANONICAL for NODE and related types. */
static void static void
lto_register_canonical_types (tree node) lto_register_canonical_types (tree node, bool first_p)
{ {
if (!node if (!node
|| !TYPE_P (node)) || !TYPE_P (node))
return; return;
TYPE_CANONICAL (node) = NULL_TREE; if (first_p)
TYPE_CANONICAL (node) = gimple_register_canonical_type (node); TYPE_CANONICAL (node) = NULL_TREE;
if (POINTER_TYPE_P (node) if (POINTER_TYPE_P (node)
|| TREE_CODE (node) == COMPLEX_TYPE || TREE_CODE (node) == COMPLEX_TYPE
|| TREE_CODE (node) == ARRAY_TYPE) || TREE_CODE (node) == ARRAY_TYPE)
lto_register_canonical_types (TREE_TYPE (node)); lto_register_canonical_types (TREE_TYPE (node), first_p);
if (!first_p)
gimple_register_canonical_type (node);
} }
@ -1845,7 +1881,7 @@ lto_read_decls (struct lto_file_decl_data *decl_data, const void *data,
/* Compute the canonical type of all types. /* Compute the canonical type of all types.
??? Should be able to assert that !TYPE_CANONICAL. */ ??? Should be able to assert that !TYPE_CANONICAL. */
if (TYPE_P (t) && !TYPE_CANONICAL (t)) if (TYPE_P (t) && !TYPE_CANONICAL (t))
TYPE_CANONICAL (t) = gimple_register_canonical_type (t); gimple_register_canonical_type (t);
/* Link shared INTEGER_CSTs into TYPE_CACHED_VALUEs of its /* Link shared INTEGER_CSTs into TYPE_CACHED_VALUEs of its
type which is also member of this SCC. */ type which is also member of this SCC. */
if (TREE_CODE (t) == INTEGER_CST if (TREE_CODE (t) == INTEGER_CST
@ -2753,13 +2789,20 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
/* Register the common node types with the canonical type machinery so /* Register the common node types with the canonical type machinery so
we properly share alias-sets across languages and TUs. Do not we properly share alias-sets across languages and TUs. Do not
expose the common nodes as type merge target - those that should be expose the common nodes as type merge target - those that should be
are already exposed so by pre-loading the LTO streamer caches. */ are already exposed so by pre-loading the LTO streamer caches.
Do two passes - first clear TYPE_CANONICAL and then re-compute it. */
for (i = 0; i < itk_none; ++i) for (i = 0; i < itk_none; ++i)
lto_register_canonical_types (integer_types[i]); lto_register_canonical_types (integer_types[i], true);
/* The sizetypes are not used to access data so we do not need to for (i = 0; i < stk_type_kind_last; ++i)
do anything about them. */ lto_register_canonical_types (sizetype_tab[i], true);
for (i = 0; i < TI_MAX; ++i) for (i = 0; i < TI_MAX; ++i)
lto_register_canonical_types (global_trees[i]); lto_register_canonical_types (global_trees[i], true);
for (i = 0; i < itk_none; ++i)
lto_register_canonical_types (integer_types[i], false);
for (i = 0; i < stk_type_kind_last; ++i)
lto_register_canonical_types (sizetype_tab[i], false);
for (i = 0; i < TI_MAX; ++i)
lto_register_canonical_types (global_trees[i], false);
if (!quiet_flag) if (!quiet_flag)
fprintf (stderr, "Reading object files:"); fprintf (stderr, "Reading object files:");