On 1/18/07, Richard Kenner <[EMAIL PROTECTED]> wrote:
> I had thought of a hash table, too, but I couldn't figure out where to
> initialize and free it (i.e. where it is a "live" table, so to speak). For
> example, I don't know if this table would be required after gimplification,
> and I also don't even know how GNAT translates its own representation to
> GIMPLE (whole translation unit at once? function at a time?).
It's fairly conventional in that part.
But that's not relevant here. This is used for transmitting location
information on FIELD_DECLs back to the front end. Most records in Ada are
defined at GCC's global level, so there's little point in doing anything
other than a hash table that's initialized early on (e.g., in the routine
"gigi") and never freed. Also, the current code just saves the result for
EXPR_P nodes since only those have TREE_COMPLEXITY, but if you're switching
to a hash table, it's probably best just to record *all* results in it.
OK, attached is the preliminary hack I created some time ago. After
some changes, it now bootstraps, but I haven't tested it yet. I'm
passing it as an RFC.
I did not go as far as what you suggested, because I don't want to
change code I don't really understand. This is the minimum patch I
would need to remove the complexity field from struct tree_exp. If
one of you can do better than this, for the purpose of GNAT, please go
ahead and change it any way you see fit ;-)
No point in getting too sophisticated here: this is just a small hack to
avoid pathalogical compile-time behavior when compiling certain very complex
record types.
Are these test cases in the FSF test suite?
Thanks,
Gr.
Steven
2007-xx-xx Steven Bosscher <[EMAIL PROTECTED]>
gcc/
* tree.c (iterative_hash_expr): Handle types generically.
Also handle PLACEHOLDER_EXPR nodes.
ada/
* decl.c: Include hashtab.h and gt-ada-decl.h
(struct cached_annotate_value_t, cached_annotate_value_tab,
cached_annotate_value_hash, cached_annotate_value_eq,
cached_annotate_value_marked_p, cached_annotate_value_lookup,
cached_annotate_value_insert): New data structures and support
functions to implement a cache for annotate_value results.
(annotate_value): Use the hash table as a cache, instead of
using TREE_COMPLEXITY.
Index: tree.c
===================================================================
--- tree.c (revision 121230)
+++ tree.c (working copy)
@@ -5158,12 +5158,21 @@ iterative_hash_expr (tree t, hashval_t v
/* DECL's have a unique ID */
val = iterative_hash_host_wide_int (DECL_UID (t), val);
}
+ else if (class == tcc_type)
+ {
+ /* TYPEs also have a unique ID. */
+ val = iterative_hash_host_wide_int (TYPE_UID (t), val);
+ }
else
{
- gcc_assert (IS_EXPR_CODE_CLASS (class));
-
val = iterative_hash_object (code, val);
+ /* The tree must be a placeholder now, or an expression.
+ For anything else, die. */
+ if (code == PLACEHOLDER_EXPR)
+ return val;
+ gcc_assert (IS_EXPR_CODE_CLASS (class));
+
/* Don't hash the type, that can lead to having nodes which
compare equal according to operand_equal_p, but which
have different hash codes. */
Index: ada/decl.c
===================================================================
--- ada/decl.c (revision 121230)
+++ ada/decl.c (working copy)
@@ -34,6 +34,7 @@
#include "convert.h"
#include "ggc.h"
#include "obstack.h"
+#include "hashtab.h"
#include "target.h"
#include "expr.h"
@@ -5864,6 +5865,104 @@ compare_field_bitpos (const PTR rt1, con
return 1;
}
+
+/* In annotate_value, we compute an Uint to be placed into an Esize,
+ Component_Bit_Offset, or Component_Size value in the GNAT tree.
+ Because re-computing the value is expensive, we cache the unique
+ result for each tree in a hash table. The hash table key is the
+ hashed GNU tree, and the hash table value is the useful data in
+ the buckets.
+
+ The hash table entries are pointers to cached_annotate_value_t.
+ We hash GNU_SIZE in the insert and lookup functions for this
+ the hash table, using iterative_hash_expr. Caching the hash
+ value on the bucket entries speeds up the hash table quite a
+ bit during resizing. */
+
+struct cached_annotate_value_t GTY(())
+{
+ /* Cached hash value for this table entry. */
+ hashval_t hashval;
+
+ /* The cached value.
+ ??? This should be an Uint but gengtype choques on that. */
+ int value;
+
+ /* The tree that the value was computed for. */
+ tree gnu_size;
+};
+
+/* The hash table used as the annotate_value cache. */
+static GTY ((if_marked ("cached_annotate_value_marked_p"),
+ param_is (struct cached_annotate_value_t)))
+ htab_t cached_annotate_value_tab;
+
+/* Hash an annotate_value result for the annotate_value cache.
+ But actually, we've stored the hash value on the cache entry. */
+
+static unsigned int
+cached_annotate_value_hash (const void *pa)
+{
+ const struct cached_annotate_value_t *a = pa;
+ return a->hashval;
+}
+
+/* Return true if the tree in the annotate_value cache entries are equal. */
+
+static int
+cached_annotate_value_eq (const void *pa, const void *pb)
+{
+ const struct cached_annotate_value_t *a = pa, *b = pb;
+ int equal = (a->gnu_size == b->gnu_size);
+ return equal;
+}
+
+/* Return true if the tree in a annotate_value cache entry was marked
+ during a ggc_collect. */
+static int
+cached_annotate_value_marked_p (const void *p)
+{
+ tree gnu_size = ((struct cached_annotate_value_t *) p)->gnu_size;
+ return ggc_marked_p (gnu_size);
+}
+
+/* Lookup a cached annotate_value for GNU_SIZE.
+ If a cache entry is found, return TRUE and set the value of
+ the cache entry in VALUEP.
+ Return FALSE if none was found. */
+
+static bool
+cached_annotate_value_lookup (tree gnu_size, Uint *valuep)
+{
+ struct cached_annotate_value_t *entry, in;
+ in.gnu_size = gnu_size;
+ entry = htab_find_with_hash (cached_annotate_value_tab, &in,
+ iterative_hash_expr (gnu_size, 0));
+ if (!entry)
+ return false;
+
+ *valuep = entry->value;
+ return true;
+}
+
+/* Insert a mapping GNU_SIZE->ANNOTATE_VALUE in the annotate_value cache. */
+
+static void
+cached_annotate_value_insert (tree gnu_size, Uint value)
+{
+ struct cached_annotate_value_t *entry;
+ void **loc;
+
+ entry = ggc_alloc (sizeof (struct cached_annotate_value_t));
+ entry->hashval = iterative_hash_expr (gnu_size, 0);
+ entry->value = value;
+ entry->gnu_size = gnu_size;
+
+ loc = htab_find_slot_with_hash (cached_annotate_value_tab, entry,
+ entry->hashval, INSERT);
+ *(struct cached_annotate_value_t**) loc = entry;
+}
+
/* Given GNU_SIZE, a GCC tree representing a size, return a Uint to be
placed into an Esize, Component_Bit_Offset, or Component_Size value
in the GNAT tree. */
@@ -5876,10 +5975,20 @@ annotate_value (tree gnu_size)
Node_Ref_Or_Val ops[3], ret;
int i;
int size;
+ Uint value;
+
+ /* If the hash table to cache results of this function does not
+ already exist, create it now. */
+ if (!cached_annotate_value_tab)
+ {
+ cached_annotate_value_tab =
+ htab_create_ggc (512, cached_annotate_value_hash,
+ cached_annotate_value_eq, NULL);
+ }
/* See if we've already saved the value for this node. */
- if (EXPR_P (gnu_size) && TREE_COMPLEXITY (gnu_size))
- return (Node_Ref_Or_Val) TREE_COMPLEXITY (gnu_size);
+ if (cached_annotate_value_lookup (gnu_size, &value))
+ return value;
/* If we do not return inside this switch, TCODE will be set to the
code to use for a Create_Node operand and LEN (set above) will be
@@ -5994,7 +6103,7 @@ annotate_value (tree gnu_size)
}
ret = Create_Node (tcode, ops[0], ops[1], ops[2]);
- TREE_COMPLEXITY (gnu_size) = ret;
+ cached_annotate_value_insert (gnu_size, ret);
return ret;
}
@@ -6847,3 +6956,5 @@ concat_id_with_name (tree gnu_id, const
strcpy (Name_Buffer + len, suffix);
return get_identifier (Name_Buffer);
}
+
+#include "gt-ada-decl.h"