No subject
Richard Biener
richard.guenther@gmail.com
Fri Oct 26 09:54:00 GMT 2012
On Thu, Oct 25, 2012 at 10:56 PM, Lawrence Crowl <crowl@googlers.com> wrote:
> Change hash_table to support a comparator type different from the
> value type stored in the hash table. The 'find' functions now may
> take a different type from the value type. This requires introducing
> a second typedef into the Descriptor conceptual type. Change the
> Descriptor concept to use typedefs value_type and compare_type instead
> of T. Change all users to match.
>
> Add usage documentation to hash-table.h.
>
> Tested on x86-64.
>
> Okay for trunk?
Can you elaborate on why this is needed?
Thanks,
Richard.
>
> Index: gcc/ChangeLog
>
> 2012-10-25 Lawrence Crowl <crowl@google.com>
>
> * hash-table.h: Add usage documentation.
> (template struct typed_free_remove): Clarify documentation.
> Rename template parameter.
> (struct typed_noop_remove): Likewise.
> (descriptor concept): Change typedef T to value_type.
> Add typedef compare_type. Use more precise template parameter name,
> Descriptor instead of Descr. Update users to match.
> (struct hash_table): Change 'find' parameters to use compare_type
> instead of the value type.
>
>
> Index: gcc/tree-ssa-tail-merge.c
> ===================================================================
> --- gcc/tree-ssa-tail-merge.c (revision 192820)
> +++ gcc/tree-ssa-tail-merge.c (working copy)
> @@ -226,10 +226,11 @@ struct same_succ_def
> hashval_t hashval;
>
> /* hash_table support. */
> - typedef same_succ_def T;
> - static inline hashval_t hash (const same_succ_def *);
> - static int equal (const same_succ_def *, const same_succ_def *);
> - static void remove (same_succ_def *);
> + typedef same_succ_def value_type;
> + typedef same_succ_def compare_type;
> + static inline hashval_t hash (const value_type *);
> + static int equal (const value_type *, const compare_type *);
> + static void remove (value_type *);
> };
> typedef struct same_succ_def *same_succ;
> typedef const struct same_succ_def *const_same_succ;
> @@ -237,7 +238,7 @@ typedef const struct same_succ_def *cons
> /* hash routine for hash_table support, returns hashval of E. */
>
> inline hashval_t
> -same_succ_def::hash (const same_succ_def *e)
> +same_succ_def::hash (const value_type *e)
> {
> return e->hashval;
> }
> @@ -528,7 +529,7 @@ inverse_flags (const_same_succ e1, const
> /* Compares SAME_SUCCs E1 and E2. */
>
> int
> -same_succ_def::equal (const_same_succ e1, const_same_succ e2)
> +same_succ_def::equal (const value_type *e1, const compare_type *e2)
> {
> unsigned int i, first1, first2;
> gimple_stmt_iterator gsi1, gsi2;
> Index: gcc/tree-ssa-threadupdate.c
> ===================================================================
> --- gcc/tree-ssa-threadupdate.c (revision 192820)
> +++ gcc/tree-ssa-threadupdate.c (working copy)
> @@ -127,20 +127,21 @@ struct redirection_data : typed_free_rem
> struct el *incoming_edges;
>
> /* hash_table support. */
> - typedef redirection_data T;
> - static inline hashval_t hash (const redirection_data *);
> - static inline int equal (const redirection_data *, const redirection_data *);
> + typedef redirection_data value_type;
> + typedef redirection_data compare_type;
> + static inline hashval_t hash (const value_type *);
> + static inline int equal (const value_type *, const compare_type *);
> };
>
> inline hashval_t
> -redirection_data::hash (const redirection_data *p)
> +redirection_data::hash (const value_type *p)
> {
> edge e = p->outgoing_edge;
> return e->dest->index;
> }
>
> inline int
> -redirection_data::equal (const redirection_data *p1, const
> redirection_data *p2)
> +redirection_data::equal (const value_type *p1, const compare_type *p2)
> {
> edge e1 = p1->outgoing_edge;
> edge e2 = p2->outgoing_edge;
> Index: gcc/java/jcf-io.c
> ===================================================================
> --- gcc/java/jcf-io.c (revision 192820)
> +++ gcc/java/jcf-io.c (working copy)
> @@ -276,19 +276,21 @@ find_classfile (char *filename, JCF *jcf
>
> struct charstar_hash : typed_noop_remove <char>
> {
> - typedef const char T;
> - static inline hashval_t hash (const T *candidate);
> - static inline bool equal (const T *existing, const T *candidate);
> + typedef const char value_type;
> + typedef const char compare_type;
> + static inline hashval_t hash (const value_type *candidate);
> + static inline bool equal (const value_type *existing,
> + const compare_type *candidate);
> };
>
> inline hashval_t
> -charstar_hash::hash (const T *candidate)
> +charstar_hash::hash (const value_type *candidate)
> {
> return htab_hash_string (candidate);
> }
>
> inline bool
> -charstar_hash::equal (const T *existing, const T *candidate)
> +charstar_hash::equal (const value_type *existing, const compare_type
> *candidate)
> {
> return strcmp (existing, candidate) == 0;
> }
> Index: gcc/valtrack.h
> ===================================================================
> --- gcc/valtrack.h (revision 192820)
> +++ gcc/valtrack.h (working copy)
> @@ -46,32 +46,33 @@ struct dead_debug_global_entry
> struct dead_debug_hash_descr
> {
> /* The hash table contains pointers to entries of this type. */
> - typedef struct dead_debug_global_entry T;
> + typedef struct dead_debug_global_entry value_type;
> + typedef struct dead_debug_global_entry compare_type;
> /* Hash on the pseudo number. */
> - static inline hashval_t hash (T const *my);
> + static inline hashval_t hash (const value_type *my);
> /* Entries are identical if they refer to the same pseudo. */
> - static inline bool equal (T const *my, T const *other);
> + static inline bool equal (const value_type *my, const compare_type *other);
> /* Release entries when they're removed. */
> - static inline void remove (T *p);
> + static inline void remove (value_type *p);
> };
>
> /* Hash on the pseudo number. */
> inline hashval_t
> -dead_debug_hash_descr::hash (T const *my)
> +dead_debug_hash_descr::hash (const value_type *my)
> {
> return REGNO (my->reg);
> }
>
> /* Entries are identical if they refer to the same pseudo. */
> inline bool
> -dead_debug_hash_descr::equal (T const *my, T const *other)
> +dead_debug_hash_descr::equal (const value_type *my, const compare_type *other)
> {
> return my->reg == other->reg;
> }
>
> /* Release entries when they're removed. */
> inline void
> -dead_debug_hash_descr::remove (T *p)
> +dead_debug_hash_descr::remove (value_type *p)
> {
> XDELETE (p);
> }
> Index: gcc/objc/objc-act.c
> ===================================================================
> --- gcc/objc/objc-act.c (revision 192820)
> +++ gcc/objc/objc-act.c (working copy)
> @@ -3827,19 +3827,20 @@ objc_get_class_ivars (tree class_name)
>
> struct decl_name_hash : typed_noop_remove <tree_node>
> {
> - typedef tree_node T;
> - static inline hashval_t hash (const T *);
> - static inline bool equal (const T *, const T *);
> + typedef tree_node value_type;
> + typedef tree_node compare_type;
> + static inline hashval_t hash (const value_type *);
> + static inline bool equal (const value_type *, const compare_type *);
> };
>
> inline hashval_t
> -decl_name_hash::hash (const T *q)
> +decl_name_hash::hash (const value_type *q)
> {
> return (hashval_t) ((intptr_t)(DECL_NAME (q)) >> 3);
> }
>
> inline bool
> -decl_name_hash::equal (const T *a, const T *b)
> +decl_name_hash::equal (const value_type *a, const compare_type *b)
> {
> return DECL_NAME (a) == DECL_NAME (b);
> }
> Index: gcc/cfg.c
> ===================================================================
> --- gcc/cfg.c (revision 192820)
> +++ gcc/cfg.c (working copy)
> @@ -988,19 +988,21 @@ struct htab_bb_copy_original_entry
>
> struct bb_copy_hasher : typed_noop_remove <htab_bb_copy_original_entry>
> {
> - typedef htab_bb_copy_original_entry T;
> - static inline hashval_t hash (const T *);
> - static inline bool equal (const T *existing, const T * candidate);
> + typedef htab_bb_copy_original_entry value_type;
> + typedef htab_bb_copy_original_entry compare_type;
> + static inline hashval_t hash (const value_type *);
> + static inline bool equal (const value_type *existing,
> + const compare_type * candidate);
> };
>
> inline hashval_t
> -bb_copy_hasher::hash (const T *data)
> +bb_copy_hasher::hash (const value_type *data)
> {
> return data->index1;
> }
>
> inline bool
> -bb_copy_hasher::equal (const T *data, const T *data2)
> +bb_copy_hasher::equal (const value_type *data, const compare_type *data2)
> {
> return data->index1 == data2->index1;
> }
> Index: gcc/hash-table.h
> ===================================================================
> --- gcc/hash-table.h (revision 192820)
> +++ gcc/hash-table.h (working copy)
> @@ -21,7 +21,142 @@ along with GCC; see the file COPYING3.
>
>
> /* This file implements a typed hash table.
> - The implementation borrows from libiberty's hashtab. */
> + The implementation borrows from libiberty's htab_t in hashtab.h.
> +
> +
> + INTRODUCTION TO TYPES
> +
> + Users of the hash table generally need to be aware of three types.
> +
> + 1. The type being placed into the hash table. This type is called
> + the value type.
> +
> + 2. The type used to describe how to handle the value type within
> + the hash table. This descriptor type provides the hash table with
> + several things.
> +
> + - A typedef named 'value_type' to the value type (from above).
> +
> + - A static member function named 'hash' that takes a value_type
> + pointer and returns a hashval_t value.
> +
> + - A typedef named 'compare_type' that is used to test when an value
> + is found. This type is the comparison type. Usually, it will be the
> + same as value_type. If it is not the same type, you must generally
> + explicitly compute hash values and pass them to the hash table.
> +
> + - A static member function named 'equal' that takes a value_type
> + pointer and a compare_type pointer, and returns a bool.
> +
> + - A static function named 'remove' that takes an value_type pointer
> + and frees the memory allocated by it. This function is used when
> + individual elements of the table need to be disposed of (e.g.,
> + when deleting a hash table, removing elements from the table, etc).
> +
> + 3. The type of the hash table itself. (More later.)
> +
> + In very special circumstances, users may need to know about a fourth type.
> +
> + 4. The template type used to describe how hash table memory
> + is allocated. This type is called the allocator type. It is
> + parameterized on the value type. It provides four functions.
> +
> + - A static member function named 'control_alloc'. This function
> + allocates the control data blocks for the table.
> +
> + - A static member function named 'control_free'. This function
> + frees the control data blocks for the table.
> +
> + - A static member function named 'data_alloc'. This function
> + allocates the data elements in the table.
> +
> + - A static member function named 'data_free'. This function
> + deallocates the data elements in the table.
> +
> + Hash table are instantiated with two type arguments.
> +
> + * The descriptor type, (2) above.
> +
> + * The allocator type, (4) above. In general, you will not need to
> + provide your own allocator type. By default, hash tables will use
> + the class template xcallocator, which uses malloc/free for allocation.
> +
> +
> + DEFINING A DESCRIPTOR TYPE
> +
> + The first task in using the hash table is to describe the element type.
> + We compose this into a few steps.
> +
> + 1. Decide on a removal policy for values stored in the table.
> + This header provides class templates for the two most common
> + policies.
> +
> + * typed_free_remove implements the static 'remove' member function
> + by calling free().
> +
> + * typed_noop_remove implements the static 'remove' member function
> + by doing nothing.
> +
> + You can use these policies by simply deriving the descriptor type
> + from one of those class template, with the appropriate argument.
> +
> + Otherwise, you need to write the static 'remove' member function
> + in the descriptor class.
> +
> + 2. Choose a hash function. Write the static 'hash' member function.
> +
> + 3. Choose an equality testing function. In most cases, its two
> + arguments will be value_type pointers. If not, the first argument must
> + be a value_type pointer, and the second argument a compare_type pointer.
> +
> +
> + AN EXAMPLE DESCRIPTOR TYPE
> +
> + Suppose you want to put some_type into the hash table. You could define
> + the descriptor type as follows.
> +
> + struct some_type_hasher : typed_noop_remove <some_type>
> + // Deriving from typed_noop_remove means that we get a 'remove' that does
> + // nothing. This choice is good for raw values.
> + {
> + typedef some_type value_type;
> + typedef some_type compare_type;
> + static inline hashval_t hash (const value_type *);
> + static inline bool equal (const value_type *, const compare_type *);
> + };
> +
> + inline hashval_t
> + some_type_hasher::hash (const value_type *e)
> + { ... compute and return a hash value for E ... }
> +
> + inline bool
> + some_type_hasher::equal (const value_type *p1, const compare_type *p2)
> + { ... compare P1 vs P2. Return true if they are the 'same' ... }
> +
> +
> + AN EXAMPLE HASH_TABLE DECLARATION
> +
> + To instantiate a hash table for some_type:
> +
> + hash_table <some_type_hasher> some_type_hash_table;
> +
> + There is no need to mention some_type directly, as the hash table will
> + obtain it using some_type_hasher::value_type.
> +
> + You can then used any of the functions in hash_table's public interface.
> + See hash_table for details. The interface is very similar to libiberty's
> + htab_t.
> +
> +
> + EASY DESCRIPTORS FOR POINTERS
> +
> + The class template pointer_hash provides everything you need to hash
> + pointers (as opposed to what they point to). So, to instantiate a hash
> + table over pointers to whatever_type,
> +
> + hash_table <pointer_hash <whatever_type>> whatever_type_hash_table;
> +
> +*/
>
>
> #ifndef TYPED_HASHTAB_H
> @@ -53,7 +188,7 @@ xcallocator <Type>::control_alloc (size_
> }
>
>
> -/* Allocate memory for COUNT data blocks. */
> +/* Allocate memory for COUNT data blocks. */
>
> template <typename Type>
> inline Type *
> @@ -71,7 +206,7 @@ xcallocator <Type>::control_free (Type *
> {
> return ::free (memory);
> }
> -
> +
>
> /* Free memory for data blocks. */
>
> @@ -83,50 +218,71 @@ xcallocator <Type>::data_free (Type *mem
> }
>
>
> -/* Remove method dispatching to free. */
> +/* Helpful type for removing with free. */
>
> -template <typename Element>
> +template <typename Type>
> struct typed_free_remove
> {
> - static inline void remove (Element *p) { free (p); }
> + static inline void remove (Type *p);
> };
>
> -/* No-op remove method. */
>
> -template <typename Element>
> +/* Remove with free. */
> +
> +template <typename Type>
> +inline void
> +typed_free_remove <Type>::remove (Type *p)
> +{
> + free (p);
> +}
> +
> +
> +/* Helpful type for a no-op remove. */
> +
> +template <typename Type>
> struct typed_noop_remove
> {
> - static inline void remove (Element *) {}
> + static inline void remove (Type *p);
> };
>
>
> +/* Remove doing nothing. */
> +
> +template <typename Type>
> +inline void
> +typed_noop_remove <Type>::remove (Type *p ATTRIBUTE_UNUSED)
> +{
> +}
> +
> +
> /* Pointer hash with a no-op remove method. */
>
> -template <typename Element>
> -struct pointer_hash : typed_noop_remove <Element>
> +template <typename Type>
> +struct pointer_hash : typed_noop_remove <Type>
> {
> - typedef Element T;
> + typedef Type value_type;
> + typedef Type compare_type;
>
> static inline hashval_t
> - hash (const T *);
> + hash (const value_type *);
>
> static inline int
> - equal (const T *existing, const T * candidate);
> + equal (const value_type *existing, const compare_type *candidate);
> };
>
> -template <typename Element>
> +template <typename Type>
> inline hashval_t
> -pointer_hash<Element>::hash (const T *candidate)
> +pointer_hash <Type>::hash (const value_type *candidate)
> {
> /* This is a really poor hash function, but it is what the current code uses,
> so I am reusing it to avoid an additional axis in testing. */
> return (hashval_t) ((intptr_t)candidate >> 3);
> }
>
> -template <typename Element>
> +template <typename Type>
> inline int
> -pointer_hash<Element>::equal (const T *existing,
> - const T *candidate)
> +pointer_hash <Type>::equal (const value_type *existing,
> + const compare_type *candidate)
> {
> return existing == candidate;
> }
> @@ -185,37 +341,38 @@ struct hash_table_control
>
> /* User-facing hash table type.
>
> - The table stores elements of type Element.
> + The table stores elements of type Descriptor::value_type.
>
> - It hashes elements with the hash function.
> + It hashes values with the hash member function.
> The table currently works with relatively weak hash functions.
> - Use typed_pointer_hash <Element> when hashing pointers instead of objects.
> + Use typed_pointer_hash <Value> when hashing pointers instead of objects.
>
> - It compares elements with the equal function.
> + It compares elements with the equal member function.
> Two elements with the same hash may not be equal.
> - Use typed_pointer_equal <Element> when hashing pointers instead
> of objects.
> + Use typed_pointer_equal <Value> when hashing pointers instead of objects.
>
> - It removes elements with the remove function.
> + It removes elements with the remove member function.
> This feature is useful for freeing memory.
> - Use typed_null_remove <Element> when not freeing objects.
> - Use typed_free_remove <Element> when doing a simple object free.
> + Derive from typed_null_remove <Value> when not freeing objects.
> + Derive from typed_free_remove <Value> when doing a simple object free.
>
> - Use the Allocator template to allocate and free memory.
> + Specify the template Allocator to allocate and free memory.
> The default is xcallocator.
>
> */
>
> -template <typename Descr,
> +template <typename Descriptor,
> template <typename Type> class Allocator = xcallocator>
> class hash_table
> {
> public:
> - typedef typename Descr::T T;
> + typedef typename Descriptor::value_type value_type;
> + typedef typename Descriptor::compare_type compare_type;
>
> private:
> - hash_table_control <T> *htab;
> + hash_table_control <value_type> *htab;
>
> - T **find_empty_slot_for_expand (hashval_t hash);
> + value_type **find_empty_slot_for_expand (hashval_t hash);
> void expand ();
>
> public:
> @@ -223,35 +380,36 @@ public:
> void create (size_t initial_slots);
> bool is_created ();
> void dispose ();
> - T *find (const T *comparable);
> - T *find_with_hash (const T *comparable, hashval_t hash);
> - T **find_slot (const T *comparable, enum insert_option insert);
> - T **find_slot_with_hash (const T *comparable, hashval_t hash,
> - enum insert_option insert);
> + value_type *find (const compare_type *comparable);
> + value_type *find_with_hash (const compare_type *comparable, hashval_t hash);
> + value_type **find_slot (const compare_type *comparable,
> + enum insert_option insert);
> + value_type **find_slot_with_hash (const compare_type *comparable,
> + hashval_t hash, enum insert_option insert);
> void empty ();
> - void clear_slot (T **slot);
> - void remove_elt (const T *comparable);
> - void remove_elt_with_hash (const T *comparable, hashval_t hash);
> + void clear_slot (value_type **slot);
> + void remove_elt (const compare_type *comparable);
> + void remove_elt_with_hash (const compare_type *comparable, hashval_t hash);
> size_t size();
> size_t elements();
> double collisions();
>
> template <typename Argument,
> - int (*Callback) (T **slot, Argument argument)>
> + int (*Callback) (value_type **slot, Argument argument)>
> void traverse_noresize (Argument argument);
>
> template <typename Argument,
> - int (*Callback) (T **slot, Argument argument)>
> + int (*Callback) (value_type **slot, Argument argument)>
> void traverse (Argument argument);
> };
>
>
> /* Construct the hash table. The only useful operation next is create. */
>
> -template <typename Descr,
> +template <typename Descriptor,
> template <typename Type> class Allocator>
> inline
> -hash_table <Descr, Allocator>::hash_table ()
> +hash_table <Descriptor, Allocator>::hash_table ()
> : htab (NULL)
> {
> }
> @@ -259,10 +417,10 @@ hash_table <Descr, Allocator>::hash_tabl
>
> /* See if the table has been created, as opposed to constructed. */
>
> -template <typename Descr,
> +template <typename Descriptor,
> template <typename Type> class Allocator>
> inline bool
> -hash_table <Descr, Allocator>::is_created ()
> +hash_table <Descriptor, Allocator>::is_created ()
> {
> return htab != NULL;
> }
> @@ -270,45 +428,44 @@ hash_table <Descr, Allocator>::is_create
>
> /* Like find_with_hash, but compute the hash value from the element. */
>
> -template <typename Descr,
> +template <typename Descriptor,
> template <typename Type> class Allocator>
> -inline typename Descr::T *
> -hash_table <Descr, Allocator>::find (const T *comparable)
> +inline typename Descriptor::value_type *
> +hash_table <Descriptor, Allocator>::find (const compare_type *comparable)
> {
> - return find_with_hash (comparable, Descr::hash (comparable));
> + return find_with_hash (comparable, Descriptor::hash (comparable));
> }
>
>
> /* Like find_slot_with_hash, but compute the hash value from the element. */
>
> -template <typename Descr,
> +template <typename Descriptor,
> template <typename Type> class Allocator>
> -inline typename Descr::T **
> -hash_table <Descr, Allocator>
> -::find_slot (const T *comparable, enum insert_option insert)
> +inline typename Descriptor::value_type **
> +hash_table <Descriptor, Allocator>
> +::find_slot (const compare_type *comparable, enum insert_option insert)
> {
> - return find_slot_with_hash (comparable, Descr::hash (comparable), insert);
> + return find_slot_with_hash (comparable, Descriptor::hash
> (comparable), insert);
> }
>
>
> /* Like remove_elt_with_hash, but compute the hash value from the element. */
>
> -template <typename Descr,
> +template <typename Descriptor,
> template <typename Type> class Allocator>
> inline void
> -hash_table <Descr, Allocator>
> -::remove_elt (const T *comparable)
> +hash_table <Descriptor, Allocator>::remove_elt (const compare_type *comparable)
> {
> - remove_elt_with_hash (comparable, Descr::hash (comparable));
> + remove_elt_with_hash (comparable, Descriptor::hash (comparable));
> }
>
>
> /* Return the current size of this hash table. */
>
> -template <typename Descr,
> +template <typename Descriptor,
> template <typename Type> class Allocator>
> inline size_t
> -hash_table <Descr, Allocator>::size()
> +hash_table <Descriptor, Allocator>::size()
> {
> return htab->size;
> }
> @@ -316,10 +473,10 @@ hash_table <Descr, Allocator>::size()
>
> /* Return the current number of elements in this hash table. */
>
> -template <typename Descr,
> +template <typename Descriptor,
> template <typename Type> class Allocator>
> inline size_t
> -hash_table <Descr, Allocator>::elements()
> +hash_table <Descriptor, Allocator>::elements()
> {
> return htab->n_elements - htab->n_deleted;
> }
> @@ -328,10 +485,10 @@ hash_table <Descr, Allocator>::elements(
> /* Return the fraction of fixed collisions during all work with given
> hash table. */
>
> -template <typename Descr,
> +template <typename Descriptor,
> template <typename Type> class Allocator>
> inline double
> -hash_table <Descr, Allocator>::collisions()
> +hash_table <Descriptor, Allocator>::collisions()
> {
> if (htab->searches == 0)
> return 0.0;
> @@ -342,19 +499,19 @@ hash_table <Descr, Allocator>::collision
>
> /* Create a hash table with at least the given number of INITIAL_SLOTS. */
>
> -template <typename Descr,
> +template <typename Descriptor,
> template <typename Type> class Allocator>
> void
> -hash_table <Descr, Allocator>::create (size_t size)
> +hash_table <Descriptor, Allocator>::create (size_t size)
> {
> unsigned int size_prime_index;
>
> size_prime_index = hash_table_higher_prime_index (size);
> size = prime_tab[size_prime_index].prime;
>
> - htab = Allocator <hash_table_control <T> > ::control_alloc (1);
> + htab = Allocator <hash_table_control <value_type> > ::control_alloc (1);
> gcc_assert (htab != NULL);
> - htab->entries = Allocator <T*> ::data_alloc (size);
> + htab->entries = Allocator <value_type*> ::data_alloc (size);
> gcc_assert (htab->entries != NULL);
> htab->size = size;
> htab->size_prime_index = size_prime_index;
> @@ -364,20 +521,20 @@ hash_table <Descr, Allocator>::create (s
> /* Dispose of a hash table. Free all memory and return this hash table to
> the non-created state. Naturally the hash table must already exist. */
>
> -template <typename Descr,
> +template <typename Descriptor,
> template <typename Type> class Allocator>
> void
> -hash_table <Descr, Allocator>::dispose ()
> +hash_table <Descriptor, Allocator>::dispose ()
> {
> size_t size = htab->size;
> - T **entries = htab->entries;
> + value_type **entries = htab->entries;
>
> for (int i = size - 1; i >= 0; i--)
> if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY)
> - Descr::remove (entries[i]);
> + Descriptor::remove (entries[i]);
>
> - Allocator <T *> ::data_free (entries);
> - Allocator <hash_table_control <T> > ::control_free (htab);
> + Allocator <value_type *> ::data_free (entries);
> + Allocator <hash_table_control <value_type> > ::control_free (htab);
> htab = NULL;
> }
>
> @@ -389,15 +546,14 @@ hash_table <Descr, Allocator>::dispose (
> This function also assumes there are no deleted entries in the table.
> HASH is the hash value for the element to be inserted. */
>
> -template <typename Descr,
> +template <typename Descriptor,
> template <typename Type> class Allocator>
> -typename Descr::T **
> -hash_table <Descr, Allocator>
> -::find_empty_slot_for_expand (hashval_t hash)
> +typename Descriptor::value_type **
> +hash_table <Descriptor, Allocator>::find_empty_slot_for_expand (hashval_t hash)
> {
> hashval_t index = hash_table_mod1 (hash, htab->size_prime_index);
> size_t size = htab->size;
> - T **slot = htab->entries + index;
> + value_type **slot = htab->entries + index;
> hashval_t hash2;
>
> if (*slot == HTAB_EMPTY_ENTRY)
> @@ -428,15 +584,15 @@ hash_table <Descr, Allocator>
> table entries is changed. If memory allocation fails, this function
> will abort. */
>
> -template <typename Descr,
> +template <typename Descriptor,
> template <typename Type> class Allocator>
> void
> -hash_table <Descr, Allocator>::expand ()
> +hash_table <Descriptor, Allocator>::expand ()
> {
> - T **oentries;
> - T **olimit;
> - T **p;
> - T **nentries;
> + value_type **oentries;
> + value_type **olimit;
> + value_type **p;
> + value_type **nentries;
> size_t nsize, osize, elts;
> unsigned int oindex, nindex;
>
> @@ -459,7 +615,7 @@ hash_table <Descr, Allocator>::expand ()
> nsize = osize;
> }
>
> - nentries = Allocator <T *> ::data_alloc (nsize);
> + nentries = Allocator <value_type *> ::data_alloc (nsize);
> gcc_assert (nentries != NULL);
> htab->entries = nentries;
> htab->size = nsize;
> @@ -470,11 +626,11 @@ hash_table <Descr, Allocator>::expand ()
> p = oentries;
> do
> {
> - T *x = *p;
> + value_type *x = *p;
>
> if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY)
> {
> - T **q = find_empty_slot_for_expand (Descr::hash (x));
> + value_type **q = find_empty_slot_for_expand (Descriptor::hash (x));
>
> *q = x;
> }
> @@ -483,7 +639,7 @@ hash_table <Descr, Allocator>::expand ()
> }
> while (p < olimit);
>
> - Allocator <T *> ::data_free (oentries);
> + Allocator <value_type *> ::data_free (oentries);
> }
>
>
> @@ -491,15 +647,15 @@ hash_table <Descr, Allocator>::expand ()
> COMPARABLE element starting with the given HASH value. It cannot
> be used to insert or delete an element. */
>
> -template <typename Descr,
> +template <typename Descriptor,
> template <typename Type> class Allocator>
> -typename Descr::T *
> -hash_table <Descr, Allocator>
> -::find_with_hash (const T *comparable, hashval_t hash)
> +typename Descriptor::value_type *
> +hash_table <Descriptor, Allocator>
> +::find_with_hash (const compare_type *comparable, hashval_t hash)
> {
> hashval_t index, hash2;
> size_t size;
> - T *entry;
> + value_type *entry;
>
> htab->searches++;
> size = htab->size;
> @@ -507,7 +663,7 @@ hash_table <Descr, Allocator>
>
> entry = htab->entries[index];
> if (entry == HTAB_EMPTY_ENTRY
> - || (entry != HTAB_DELETED_ENTRY && Descr::equal (entry, comparable)))
> + || (entry != HTAB_DELETED_ENTRY && Descriptor::equal (entry,
> comparable)))
> return entry;
>
> hash2 = hash_table_mod2 (hash, htab->size_prime_index);
> @@ -520,7 +676,8 @@ hash_table <Descr, Allocator>
>
> entry = htab->entries[index];
> if (entry == HTAB_EMPTY_ENTRY
> - || (entry != HTAB_DELETED_ENTRY && Descr::equal (entry, comparable)))
> + || (entry != HTAB_DELETED_ENTRY
> + && Descriptor::equal (entry, comparable)))
> return entry;
> }
> }
> @@ -534,17 +691,17 @@ hash_table <Descr, Allocator>
> write the value you want into the returned slot. When inserting an
> entry, NULL may be returned if memory allocation fails. */
>
> -template <typename Descr,
> +template <typename Descriptor,
> template <typename Type> class Allocator>
> -typename Descr::T **
> -hash_table <Descr, Allocator>
> -::find_slot_with_hash (const T *comparable, hashval_t hash,
> +typename Descriptor::value_type **
> +hash_table <Descriptor, Allocator>
> +::find_slot_with_hash (const compare_type *comparable, hashval_t hash,
> enum insert_option insert)
> {
> - T **first_deleted_slot;
> + value_type **first_deleted_slot;
> hashval_t index, hash2;
> size_t size;
> - T *entry;
> + value_type *entry;
>
> size = htab->size;
> if (insert == INSERT && size * 3 <= htab->n_elements * 4)
> @@ -563,9 +720,9 @@ hash_table <Descr, Allocator>
> goto empty_entry;
> else if (entry == HTAB_DELETED_ENTRY)
> first_deleted_slot = &htab->entries[index];
> - else if (Descr::equal (entry, comparable))
> + else if (Descriptor::equal (entry, comparable))
> return &htab->entries[index];
> -
> +
> hash2 = hash_table_mod2 (hash, htab->size_prime_index);
> for (;;)
> {
> @@ -573,7 +730,7 @@ hash_table <Descr, Allocator>
> index += hash2;
> if (index >= size)
> index -= size;
> -
> +
> entry = htab->entries[index];
> if (entry == HTAB_EMPTY_ENTRY)
> goto empty_entry;
> @@ -582,7 +739,7 @@ hash_table <Descr, Allocator>
> if (!first_deleted_slot)
> first_deleted_slot = &htab->entries[index];
> }
> - else if (Descr::equal (entry, comparable))
> + else if (Descriptor::equal (entry, comparable))
> return &htab->entries[index];
> }
>
> @@ -593,7 +750,7 @@ hash_table <Descr, Allocator>
> if (first_deleted_slot)
> {
> htab->n_deleted--;
> - *first_deleted_slot = static_cast <T *> (HTAB_EMPTY_ENTRY);
> + *first_deleted_slot = static_cast <value_type *> (HTAB_EMPTY_ENTRY);
> return first_deleted_slot;
> }
>
> @@ -604,18 +761,18 @@ hash_table <Descr, Allocator>
>
> /* This function clears all entries in the given hash table. */
>
> -template <typename Descr,
> +template <typename Descriptor,
> template <typename Type> class Allocator>
> void
> -hash_table <Descr, Allocator>::empty ()
> +hash_table <Descriptor, Allocator>::empty ()
> {
> size_t size = htab->size;
> - T **entries = htab->entries;
> + value_type **entries = htab->entries;
> int i;
>
> for (i = size - 1; i >= 0; i--)
> if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY)
> - Descr::remove (entries[i]);
> + Descriptor::remove (entries[i]);
>
> /* Instead of clearing megabyte, downsize the table. */
> if (size > 1024*1024 / sizeof (PTR))
> @@ -623,13 +780,13 @@ hash_table <Descr, Allocator>::empty ()
> int nindex = hash_table_higher_prime_index (1024 / sizeof (PTR));
> int nsize = prime_tab[nindex].prime;
>
> - Allocator <T *> ::data_free (htab->entries);
> - htab->entries = Allocator <T *> ::data_alloc (nsize);
> + Allocator <value_type *> ::data_free (htab->entries);
> + htab->entries = Allocator <value_type *> ::data_alloc (nsize);
> htab->size = nsize;
> htab->size_prime_index = nindex;
> }
> else
> - memset (entries, 0, size * sizeof (T *));
> + memset (entries, 0, size * sizeof (value_type *));
> htab->n_deleted = 0;
> htab->n_elements = 0;
> }
> @@ -639,19 +796,18 @@ hash_table <Descr, Allocator>::empty ()
> useful when you've already done the lookup and don't want to do it
> again. */
>
> -template <typename Descr,
> +template <typename Descriptor,
> template <typename Type> class Allocator>
> void
> -hash_table <Descr, Allocator>
> -::clear_slot (T **slot)
> +hash_table <Descriptor, Allocator>::clear_slot (value_type **slot)
> {
> if (slot < htab->entries || slot >= htab->entries + htab->size
> || *slot == HTAB_EMPTY_ENTRY || *slot == HTAB_DELETED_ENTRY)
> abort ();
>
> - Descr::remove (*slot);
> + Descriptor::remove (*slot);
>
> - *slot = static_cast <T *> (HTAB_DELETED_ENTRY);
> + *slot = static_cast <value_type *> (HTAB_DELETED_ENTRY);
> htab->n_deleted++;
> }
>
> @@ -660,21 +816,21 @@ hash_table <Descr, Allocator>
> from hash table starting with the given HASH. If there is no
> matching element in the hash table, this function does nothing. */
>
> -template <typename Descr,
> +template <typename Descriptor,
> template <typename Type> class Allocator>
> void
> -hash_table <Descr, Allocator>
> -::remove_elt_with_hash (const T *comparable, hashval_t hash)
> +hash_table <Descriptor, Allocator>
> +::remove_elt_with_hash (const compare_type *comparable, hashval_t hash)
> {
> - T **slot;
> + value_type **slot;
>
> slot = find_slot_with_hash (comparable, hash, NO_INSERT);
> if (*slot == HTAB_EMPTY_ENTRY)
> return;
>
> - Descr::remove (*slot);
> + Descriptor::remove (*slot);
>
> - *slot = static_cast <T *> (HTAB_DELETED_ENTRY);
> + *slot = static_cast <value_type *> (HTAB_DELETED_ENTRY);
> htab->n_deleted++;
> }
>
> @@ -683,23 +839,22 @@ hash_table <Descr, Allocator>
> each live entry. If CALLBACK returns false, the iteration stops.
> ARGUMENT is passed as CALLBACK's second argument. */
>
> -template <typename Descr,
> +template <typename Descriptor,
> template <typename Type> class Allocator>
> template <typename Argument,
> - int (*Callback) (typename Descr::T **slot, Argument argument)>
> + int (*Callback) (typename Descriptor::value_type **slot, Argument argument)>
> void
> -hash_table <Descr, Allocator>
> -::traverse_noresize (Argument argument)
> +hash_table <Descriptor, Allocator>::traverse_noresize (Argument argument)
> {
> - T **slot;
> - T **limit;
> + value_type **slot;
> + value_type **limit;
>
> slot = htab->entries;
> limit = slot + htab->size;
>
> do
> {
> - T *x = *slot;
> + value_type *x = *slot;
>
> if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY)
> if (! Callback (slot, argument))
> @@ -712,13 +867,13 @@ hash_table <Descr, Allocator>
> /* Like traverse_noresize, but does resize the table when it is too empty
> to improve effectivity of subsequent calls. */
>
> -template <typename Descr,
> +template <typename Descriptor,
> template <typename Type> class Allocator>
> template <typename Argument,
> - int (*Callback) (typename Descr::T **slot, Argument argument)>
> + int (*Callback) (typename Descriptor::value_type **slot,
> + Argument argument)>
> void
> -hash_table <Descr, Allocator>
> -::traverse (Argument argument)
> +hash_table <Descriptor, Allocator>::traverse (Argument argument)
> {
> size_t size = htab->size;
> if (elements () * 8 < size && size > 32)
> Index: gcc/alloc-pool.c
> ===================================================================
> --- gcc/alloc-pool.c (revision 192820)
> +++ gcc/alloc-pool.c (working copy)
> @@ -22,7 +22,7 @@ along with GCC; see the file COPYING3.
> #include "config.h"
> #include "system.h"
> #include "alloc-pool.h"
> -#include "hashtab.h"
> +#include "hash-table.h"
>
> #define align_eight(x) (((x+7) >> 3) << 3)
>
> @@ -83,38 +83,42 @@ struct alloc_pool_descriptor
> int elt_size;
> };
>
> +struct alloc_pool_hasher : typed_noop_remove <alloc_pool_descriptor>
> +{
> + typedef alloc_pool_descriptor value_type;
> + typedef char compare_type;
> + static inline hashval_t hash (const alloc_pool_descriptor *);
> + static inline bool equal (const value_type *, const compare_type *);
> +};
> +
> /* Hashtable mapping alloc_pool names to descriptors. */
> -static htab_t alloc_pool_hash;
> +static hash_table <alloc_pool_hasher> alloc_pool_hash;
>
> /* Hashtable helpers. */
> -static hashval_t
> -hash_descriptor (const void *p)
> +inline hashval_t
> +alloc_pool_hasher::hash (const value_type *d)
> {
> - const struct alloc_pool_descriptor *const d =
> - (const struct alloc_pool_descriptor * )p;
> return htab_hash_pointer (d->name);
> }
> -static int
> -eq_descriptor (const void *p1, const void *p2)
> +
> +inline bool
> +alloc_pool_hasher::equal (const value_type *d,
> + const compare_type *p2)
> {
> - const struct alloc_pool_descriptor *const d =
> - (const struct alloc_pool_descriptor *) p1;
> return d->name == p2;
> }
>
> /* For given name, return descriptor, create new if needed. */
> static struct alloc_pool_descriptor *
> -alloc_pool_descriptor (const char *name)
> +allocate_pool_descriptor (const char *name)
> {
> struct alloc_pool_descriptor **slot;
>
> - if (!alloc_pool_hash)
> - alloc_pool_hash = htab_create (10, hash_descriptor, eq_descriptor, NULL);
> + if (!alloc_pool_hash.is_created ())
> + alloc_pool_hash.create (10);
>
> - slot = (struct alloc_pool_descriptor **)
> - htab_find_slot_with_hash (alloc_pool_hash, name,
> - htab_hash_pointer (name),
> - INSERT);
> + slot = alloc_pool_hash.find_slot_with_hash (name,
> + htab_hash_pointer (name), INSERT);
> if (*slot)
> return *slot;
> *slot = XCNEW (struct alloc_pool_descriptor);
> @@ -158,7 +162,7 @@ create_alloc_pool (const char *name, siz
>
> if (GATHER_STATISTICS)
> {
> - struct alloc_pool_descriptor *desc = alloc_pool_descriptor (name);
> + struct alloc_pool_descriptor *desc = allocate_pool_descriptor (name);
> desc->elt_size = size;
> desc->created++;
> }
> @@ -205,7 +209,7 @@ empty_alloc_pool (alloc_pool pool)
>
> if (GATHER_STATISTICS)
> {
> - struct alloc_pool_descriptor *desc = alloc_pool_descriptor (pool->name);
> + struct alloc_pool_descriptor *desc = allocate_pool_descriptor
> (pool->name);
> desc->current -= (pool->elts_allocated - pool->elts_free) *
> pool->elt_size;
> }
>
> @@ -253,7 +257,7 @@ pool_alloc (alloc_pool pool)
>
> if (GATHER_STATISTICS)
> {
> - struct alloc_pool_descriptor *desc = alloc_pool_descriptor (pool->name);
> + struct alloc_pool_descriptor *desc = allocate_pool_descriptor
> (pool->name);
>
> desc->allocated += pool->elt_size;
> desc->current += pool->elt_size;
> @@ -357,7 +361,7 @@ pool_free (alloc_pool pool, void *ptr)
>
> if (GATHER_STATISTICS)
> {
> - struct alloc_pool_descriptor *desc = alloc_pool_descriptor (pool->name);
> + struct alloc_pool_descriptor *desc = allocate_pool_descriptor
> (pool->name);
> desc->current -= pool->elt_size;
> }
> }
> @@ -371,19 +375,20 @@ struct output_info
> unsigned long total_allocated;
> };
>
> -/* Called via htab_traverse. Output alloc_pool descriptor pointed out by SLOT
> - and update statistics. */
> -static int
> -print_statistics (void **slot, void *b)
> +/* Called via hash_table.traverse. Output alloc_pool descriptor pointed out by
> + SLOT and update statistics. */
> +int
> +print_alloc_pool_statistics (alloc_pool_descriptor **slot,
> + struct output_info *i)
> {
> - struct alloc_pool_descriptor *d = (struct alloc_pool_descriptor *) *slot;
> - struct output_info *i = (struct output_info *) b;
> + struct alloc_pool_descriptor *d = *slot;
>
> if (d->allocated)
> {
> - fprintf (stderr, "%-22s %6d %10lu %10lu(%10lu) %10lu(%10lu)
> %10lu(%10lu)\n", d->name,
> - d->elt_size, d->created, d->allocated, d->allocated / d->elt_size,
> - d->peak, d->peak / d->elt_size,
> + fprintf (stderr,
> + "%-22s %6d %10lu %10lu(%10lu) %10lu(%10lu) %10lu(%10lu)\n",
> + d->name, d->elt_size, d->created, d->allocated,
> + d->allocated / d->elt_size, d->peak, d->peak / d->elt_size,
> d->current, d->current / d->elt_size);
> i->total_allocated += d->allocated;
> i->total_created += d->created;
> @@ -400,14 +405,15 @@ dump_alloc_pool_statistics (void)
> if (! GATHER_STATISTICS)
> return;
>
> - if (!alloc_pool_hash)
> + if (!alloc_pool_hash.is_created ())
> return;
>
> fprintf (stderr, "\nAlloc-pool Kind Elt size Pools
> Allocated (elts) Peak (elts) Leak (elts)\n");
> fprintf (stderr,
> "--------------------------------------------------------------------------------------------------------------\n");
> info.total_created = 0;
> info.total_allocated = 0;
> - htab_traverse (alloc_pool_hash, print_statistics, &info);
> + alloc_pool_hash.traverse <struct output_info *,
> + print_alloc_pool_statistics> (&info);
> fprintf (stderr,
> "--------------------------------------------------------------------------------------------------------------\n");
> fprintf (stderr, "%-22s %7lu %10lu\n",
> "Total", info.total_created, info.total_allocated);
> Index: gcc/dse.c
> ===================================================================
> --- gcc/dse.c (revision 192820)
> +++ gcc/dse.c (working copy)
> @@ -654,19 +654,21 @@ clear_alias_set_lookup (alias_set_type a
>
> struct invariant_group_base_hasher : typed_noop_remove <group_info>
> {
> - typedef group_info T;
> - static inline hashval_t hash (const T *);
> - static inline bool equal (const T *, const T *);
> + typedef group_info value_type;
> + typedef group_info compare_type;
> + static inline hashval_t hash (const value_type *);
> + static inline bool equal (const value_type *, const compare_type *);
> };
>
> inline bool
> -invariant_group_base_hasher::equal (const T *gi1, const T *gi2)
> +invariant_group_base_hasher::equal (const value_type *gi1,
> + const compare_type *gi2)
> {
> return rtx_equal_p (gi1->rtx_base, gi2->rtx_base);
> }
>
> inline hashval_t
> -invariant_group_base_hasher::hash (const T *gi)
> +invariant_group_base_hasher::hash (const value_type *gi)
> {
> int do_not_record;
> return hash_rtx (gi->rtx_base, Pmode, &do_not_record, NULL, false);
> Index: gcc/tree-ssa-coalesce.c
> ===================================================================
> --- gcc/tree-ssa-coalesce.c (revision 192820)
> +++ gcc/tree-ssa-coalesce.c (working copy)
> @@ -1261,9 +1261,10 @@ coalesce_partitions (var_map map, ssa_co
>
> struct ssa_name_var_hash : typed_noop_remove <union tree_node>
> {
> - typedef union tree_node T;
> - static inline hashval_t hash (const_tree);
> - static inline int equal (const_tree, const_tree);
> + typedef union tree_node value_type;
> + typedef union tree_node compare_type;
> + static inline hashval_t hash (const value_type *);
> + static inline int equal (const value_type *, const compare_type *);
> };
>
> inline hashval_t
> @@ -1273,7 +1274,7 @@ ssa_name_var_hash::hash (const_tree n)
> }
>
> inline int
> -ssa_name_var_hash::equal (const_tree n1, const_tree n2)
> +ssa_name_var_hash::equal (const value_type *n1, const compare_type *n2)
> {
> return SSA_NAME_VAR (n1) == SSA_NAME_VAR (n2);
> }
> Index: gcc/coverage.c
> ===================================================================
> --- gcc/coverage.c (revision 192820)
> +++ gcc/coverage.c (working copy)
> @@ -79,10 +79,11 @@ typedef struct counts_entry
> struct gcov_ctr_summary summary;
>
> /* hash_table support. */
> - typedef counts_entry T;
> - static inline hashval_t hash (const counts_entry *);
> - static int equal (const counts_entry *, const counts_entry *);
> - static void remove (counts_entry *);
> + typedef counts_entry value_type;
> + typedef counts_entry compare_type;
> + static inline hashval_t hash (const value_type *);
> + static int equal (const value_type *, const compare_type *);
> + static void remove (value_type *);
> } counts_entry_t;
>
> static GTY(()) struct coverage_data *functions_head = 0;
> @@ -150,20 +151,20 @@ get_gcov_unsigned_t (void)
> }
>
> inline hashval_t
> -counts_entry::hash (const counts_entry_t *entry)
> +counts_entry::hash (const value_type *entry)
> {
> return entry->ident * GCOV_COUNTERS + entry->ctr;
> }
>
> inline int
> -counts_entry::equal (const counts_entry_t *entry1,
> - const counts_entry_t *entry2)
> +counts_entry::equal (const value_type *entry1,
> + const compare_type *entry2)
> {
> return entry1->ident == entry2->ident && entry1->ctr == entry2->ctr;
> }
>
> inline void
> -counts_entry::remove (counts_entry_t *entry)
> +counts_entry::remove (value_type *entry)
> {
> free (entry->counts);
> free (entry);
> Index: gcc/tree-ssa-pre.c
> ===================================================================
> --- gcc/tree-ssa-pre.c (revision 192820)
> +++ gcc/tree-ssa-pre.c (working copy)
> @@ -173,7 +173,8 @@ typedef struct pre_expr_d : typed_noop_r
> pre_expr_union u;
>
> /* hash_table support. */
> - typedef pre_expr_d T;
> + typedef pre_expr_d value_type;
> + typedef pre_expr_d compare_type;
> static inline hashval_t hash (const pre_expr_d *);
> static inline int equal (const pre_expr_d *, const pre_expr_d *);
> } *pre_expr;
> @@ -186,7 +187,7 @@ typedef struct pre_expr_d : typed_noop_r
> /* Compare E1 and E1 for equality. */
>
> inline int
> -pre_expr_d::equal (const struct pre_expr_d *e1, const struct pre_expr_d *e2)
> +pre_expr_d::equal (const value_type *e1, const compare_type *e2)
> {
> if (e1->kind != e2->kind)
> return false;
> @@ -211,7 +212,7 @@ pre_expr_d::equal (const struct pre_expr
> /* Hash E. */
>
> inline hashval_t
> -pre_expr_d::hash (const struct pre_expr_d *e)
> +pre_expr_d::hash (const value_type *e)
> {
> switch (e->kind)
> {
> @@ -499,9 +500,10 @@ typedef struct expr_pred_trans_d : typed
> hashval_t hashcode;
>
> /* hash_table support. */
> - typedef expr_pred_trans_d T;
> - static inline hashval_t hash (const expr_pred_trans_d *);
> - static inline int equal (const expr_pred_trans_d *, const
> expr_pred_trans_d *);
> + typedef expr_pred_trans_d value_type;
> + typedef expr_pred_trans_d compare_type;
> + static inline hashval_t hash (const value_type *);
> + static inline int equal (const value_type *, const compare_type *);
> } *expr_pred_trans_t;
> typedef const struct expr_pred_trans_d *const_expr_pred_trans_t;
>
> @@ -512,8 +514,8 @@ expr_pred_trans_d::hash (const expr_pred
> }
>
> inline int
> -expr_pred_trans_d::equal (const expr_pred_trans_d *ve1,
> - const expr_pred_trans_d *ve2)
> +expr_pred_trans_d::equal (const value_type *ve1,
> + const compare_type *ve2)
> {
> basic_block b1 = ve1->pred;
> basic_block b2 = ve2->pred;
>
> --
> Lawrence Crowl
More information about the Gcc-patches
mailing list