| /* An expandable hash tables datatype. | |
| Copyright (C) 1999-2026 Free Software Foundation, Inc. | |
| Contributed by Vladimir Makarov <vmakarov@cygnus.com>. | |
| This file is part of the GNU Offloading and Multi Processing Library | |
| (libgomp). | |
| Libgomp 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 3, or (at your option) | |
| any later version. | |
| Libgomp 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. | |
| Under Section 7 of GPL version 3, you are granted additional | |
| permissions described in the GCC Runtime Library Exception, version | |
| 3.1, as published by the Free Software Foundation. | |
| You should have received a copy of the GNU General Public License and | |
| a copy of the GCC Runtime Library Exception along with this program; | |
| see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
| <http://www.gnu.org/licenses/>. */ | |
| /* The hash table code copied from include/hashtab.[hc] and adjusted, | |
| so that the hash table entries are in the flexible array at the end | |
| of the control structure, no callbacks are used and the elements in the | |
| table are of the hash_entry_type type. | |
| Before including this file, define hash_entry_type type and | |
| htab_alloc and htab_free functions. After including it, define | |
| htab_hash and htab_eq inline functions. */ | |
| /* This package implements basic hash table functionality. It is possible | |
| to search for an entry, create an entry and destroy an entry. | |
| Elements in the table are generic pointers. | |
| The size of the table is not fixed; if the occupancy of the table | |
| grows too high the hash table will be expanded. | |
| The abstract data implementation is based on generalized Algorithm D | |
| from Knuth's book "The art of computer programming". Hash table is | |
| expanded by creation of new hash table and transferring elements from | |
| the old table to the new table. */ | |
| /* The type for a hash code. */ | |
| typedef unsigned int hashval_t; | |
| static inline hashval_t htab_hash (hash_entry_type); | |
| static inline bool htab_eq (hash_entry_type, hash_entry_type); | |
| /* This macro defines reserved value for empty table entry. */ | |
| #define HTAB_EMPTY_ENTRY ((hash_entry_type) 0) | |
| /* This macro defines reserved value for table entry which contained | |
| a deleted element. */ | |
| #define HTAB_DELETED_ENTRY ((hash_entry_type) 1) | |
| /* Hash tables are of the following type. The structure | |
| (implementation) of this type is not needed for using the hash | |
| tables. All work with hash table should be executed only through | |
| functions mentioned below. The size of this structure is subject to | |
| change. */ | |
| struct htab { | |
| /* Current size (in entries) of the hash table. */ | |
| size_t size; | |
| /* Current number of elements including also deleted elements. */ | |
| size_t n_elements; | |
| /* Current number of deleted elements in the table. */ | |
| size_t n_deleted; | |
| /* Current size (in entries) of the hash table, as an index into the | |
| table of primes. */ | |
| unsigned int size_prime_index; | |
| /* Table itself. */ | |
| hash_entry_type entries[]; | |
| }; | |
| typedef struct htab *htab_t; | |
| /* An enum saying whether we insert into the hash table or not. */ | |
| enum insert_option {NO_INSERT, INSERT}; | |
| /* Table of primes and multiplicative inverses. | |
| Note that these are not minimally reduced inverses. Unlike when generating | |
| code to divide by a constant, we want to be able to use the same algorithm | |
| all the time. All of these inverses (are implied to) have bit 32 set. | |
| For the record, the function that computed the table is in | |
| libiberty/hashtab.c. */ | |
| struct prime_ent | |
| { | |
| hashval_t prime; | |
| hashval_t inv; | |
| hashval_t inv_m2; /* inverse of prime-2 */ | |
| hashval_t shift; | |
| }; | |
| static struct prime_ent const prime_tab[] = { | |
| { 7, 0x24924925, 0x9999999b, 2 }, | |
| { 13, 0x3b13b13c, 0x745d1747, 3 }, | |
| { 31, 0x08421085, 0x1a7b9612, 4 }, | |
| { 61, 0x0c9714fc, 0x15b1e5f8, 5 }, | |
| { 127, 0x02040811, 0x0624dd30, 6 }, | |
| { 251, 0x05197f7e, 0x073260a5, 7 }, | |
| { 509, 0x01824366, 0x02864fc8, 8 }, | |
| { 1021, 0x00c0906d, 0x014191f7, 9 }, | |
| { 2039, 0x0121456f, 0x0161e69e, 10 }, | |
| { 4093, 0x00300902, 0x00501908, 11 }, | |
| { 8191, 0x00080041, 0x00180241, 12 }, | |
| { 16381, 0x000c0091, 0x00140191, 13 }, | |
| { 32749, 0x002605a5, 0x002a06e6, 14 }, | |
| { 65521, 0x000f00e2, 0x00110122, 15 }, | |
| { 131071, 0x00008001, 0x00018003, 16 }, | |
| { 262139, 0x00014002, 0x0001c004, 17 }, | |
| { 524287, 0x00002001, 0x00006001, 18 }, | |
| { 1048573, 0x00003001, 0x00005001, 19 }, | |
| { 2097143, 0x00004801, 0x00005801, 20 }, | |
| { 4194301, 0x00000c01, 0x00001401, 21 }, | |
| { 8388593, 0x00001e01, 0x00002201, 22 }, | |
| { 16777213, 0x00000301, 0x00000501, 23 }, | |
| { 33554393, 0x00001381, 0x00001481, 24 }, | |
| { 67108859, 0x00000141, 0x000001c1, 25 }, | |
| { 134217689, 0x000004e1, 0x00000521, 26 }, | |
| { 268435399, 0x00000391, 0x000003b1, 27 }, | |
| { 536870909, 0x00000019, 0x00000029, 28 }, | |
| { 1073741789, 0x0000008d, 0x00000095, 29 }, | |
| { 2147483647, 0x00000003, 0x00000007, 30 }, | |
| /* Avoid "decimal constant so large it is unsigned" for 4294967291. */ | |
| { 0xfffffffb, 0x00000006, 0x00000008, 31 } | |
| }; | |
| /* The following function returns an index into the above table of the | |
| nearest prime number which is greater than N, and near a power of two. */ | |
| static unsigned int | |
| higher_prime_index (unsigned long n) | |
| { | |
| unsigned int low = 0; | |
| unsigned int high = sizeof(prime_tab) / sizeof(prime_tab[0]); | |
| while (low != high) | |
| { | |
| unsigned int mid = low + (high - low) / 2; | |
| if (n > prime_tab[mid].prime) | |
| low = mid + 1; | |
| else | |
| high = mid; | |
| } | |
| /* If we've run out of primes, abort. */ | |
| if (n > prime_tab[low].prime) | |
| abort (); | |
| return low; | |
| } | |
| /* Return the current size of given hash table. */ | |
| static inline size_t | |
| htab_size (htab_t htab) | |
| { | |
| return htab->size; | |
| } | |
| /* Return the current number of elements in given hash table. */ | |
| static inline size_t | |
| htab_elements (htab_t htab) | |
| { | |
| return htab->n_elements - htab->n_deleted; | |
| } | |
| /* Return X % Y. */ | |
| static inline hashval_t | |
| htab_mod_1 (hashval_t x, hashval_t y, hashval_t inv, int shift) | |
| { | |
| /* The multiplicative inverses computed above are for 32-bit types, and | |
| requires that we be able to compute a highpart multiply. */ | |
| if (sizeof (hashval_t) * __CHAR_BIT__ <= 32) | |
| { | |
| hashval_t t1, t2, t3, t4, q, r; | |
| t1 = ((unsigned long long)x * inv) >> 32; | |
| t2 = x - t1; | |
| t3 = t2 >> 1; | |
| t4 = t1 + t3; | |
| q = t4 >> shift; | |
| r = x - (q * y); | |
| return r; | |
| } | |
| /* Otherwise just use the native division routines. */ | |
| return x % y; | |
| } | |
| /* Compute the primary hash for HASH given HTAB's current size. */ | |
| static inline hashval_t | |
| htab_mod (hashval_t hash, htab_t htab) | |
| { | |
| const struct prime_ent *p = &prime_tab[htab->size_prime_index]; | |
| return htab_mod_1 (hash, p->prime, p->inv, p->shift); | |
| } | |
| /* Compute the secondary hash for HASH given HTAB's current size. */ | |
| static inline hashval_t | |
| htab_mod_m2 (hashval_t hash, htab_t htab) | |
| { | |
| const struct prime_ent *p = &prime_tab[htab->size_prime_index]; | |
| return 1 + htab_mod_1 (hash, p->prime - 2, p->inv_m2, p->shift); | |
| } | |
| static inline htab_t | |
| htab_clear (htab_t htab) | |
| { | |
| htab->n_elements = 0; | |
| htab->n_deleted = 0; | |
| memset (htab->entries, 0, htab->size * sizeof (hash_entry_type)); | |
| return htab; | |
| } | |
| /* Create hash table of size SIZE. */ | |
| static htab_t | |
| htab_create (size_t size) | |
| { | |
| htab_t result; | |
| unsigned int size_prime_index; | |
| size_prime_index = higher_prime_index (size); | |
| size = prime_tab[size_prime_index].prime; | |
| result = (htab_t) htab_alloc (sizeof (struct htab) | |
| + size * sizeof (hash_entry_type)); | |
| result->size = size; | |
| result->size_prime_index = size_prime_index; | |
| return htab_clear (result); | |
| } | |
| /* Similar to htab_find_slot, but without several unwanted side effects: | |
| - Does not call htab_eq when it finds an existing entry. | |
| - Does not change the count of elements in the hash table. | |
| This function also assumes there are no deleted entries in the table. | |
| HASH is the hash value for the element to be inserted. */ | |
| static hash_entry_type * | |
| find_empty_slot_for_expand (htab_t htab, hashval_t hash) | |
| { | |
| hashval_t index = htab_mod (hash, htab); | |
| size_t size = htab_size (htab); | |
| hash_entry_type *slot = htab->entries + index; | |
| hashval_t hash2; | |
| if (*slot == HTAB_EMPTY_ENTRY) | |
| return slot; | |
| else if (*slot == HTAB_DELETED_ENTRY) | |
| abort (); | |
| hash2 = htab_mod_m2 (hash, htab); | |
| for (;;) | |
| { | |
| index += hash2; | |
| if (index >= size) | |
| index -= size; | |
| slot = htab->entries + index; | |
| if (*slot == HTAB_EMPTY_ENTRY) | |
| return slot; | |
| else if (*slot == HTAB_DELETED_ENTRY) | |
| abort (); | |
| } | |
| } | |
| /* The following function changes size of memory allocated for the | |
| entries and repeatedly inserts the table elements. The occupancy | |
| of the table after the call will be about 50%. Naturally the hash | |
| table must already exist. Remember also that the place of the | |
| table entries is changed. */ | |
| static htab_t | |
| htab_expand (htab_t htab) | |
| { | |
| htab_t nhtab; | |
| hash_entry_type *olimit; | |
| hash_entry_type *p; | |
| size_t osize, elts; | |
| osize = htab->size; | |
| olimit = htab->entries + osize; | |
| elts = htab_elements (htab); | |
| /* Resize only when table after removal of unused elements is either | |
| too full or too empty. */ | |
| if (elts * 2 > osize || (elts * 8 < osize && osize > 32)) | |
| nhtab = htab_create (elts * 2); | |
| else | |
| nhtab = htab_create (osize - 1); | |
| nhtab->n_elements = htab->n_elements - htab->n_deleted; | |
| p = htab->entries; | |
| do | |
| { | |
| hash_entry_type x = *p; | |
| if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY) | |
| *find_empty_slot_for_expand (nhtab, htab_hash (x)) = x; | |
| p++; | |
| } | |
| while (p < olimit); | |
| htab_free (htab); | |
| return nhtab; | |
| } | |
| /* This function searches for a hash table entry equal to the given | |
| element. It cannot be used to insert or delete an element. */ | |
| static hash_entry_type | |
| htab_find (htab_t htab, const hash_entry_type element) | |
| { | |
| hashval_t index, hash2, hash = htab_hash (element); | |
| size_t size; | |
| hash_entry_type entry; | |
| size = htab_size (htab); | |
| index = htab_mod (hash, htab); | |
| entry = htab->entries[index]; | |
| if (entry == HTAB_EMPTY_ENTRY | |
| || (entry != HTAB_DELETED_ENTRY && htab_eq (entry, element))) | |
| return entry; | |
| hash2 = htab_mod_m2 (hash, htab); | |
| for (;;) | |
| { | |
| index += hash2; | |
| if (index >= size) | |
| index -= size; | |
| entry = htab->entries[index]; | |
| if (entry == HTAB_EMPTY_ENTRY | |
| || (entry != HTAB_DELETED_ENTRY && htab_eq (entry, element))) | |
| return entry; | |
| } | |
| } | |
| /* This function searches for a hash table slot containing an entry | |
| equal to the given element. To delete an entry, call this with | |
| insert=NO_INSERT, then call htab_clear_slot on the slot returned | |
| (possibly after doing some checks). To insert an entry, call this | |
| with insert=INSERT, then write the value you want into the returned | |
| slot. */ | |
| static hash_entry_type * | |
| htab_find_slot (htab_t *htabp, const hash_entry_type element, | |
| enum insert_option insert) | |
| { | |
| hash_entry_type *first_deleted_slot; | |
| hashval_t index, hash2, hash = htab_hash (element); | |
| size_t size; | |
| hash_entry_type entry; | |
| htab_t htab = *htabp; | |
| size = htab_size (htab); | |
| if (insert == INSERT && size * 3 <= htab->n_elements * 4) | |
| { | |
| htab = *htabp = htab_expand (htab); | |
| size = htab_size (htab); | |
| } | |
| index = htab_mod (hash, htab); | |
| first_deleted_slot = NULL; | |
| entry = htab->entries[index]; | |
| if (entry == HTAB_EMPTY_ENTRY) | |
| goto empty_entry; | |
| else if (entry == HTAB_DELETED_ENTRY) | |
| first_deleted_slot = &htab->entries[index]; | |
| else if (htab_eq (entry, element)) | |
| return &htab->entries[index]; | |
| hash2 = htab_mod_m2 (hash, htab); | |
| for (;;) | |
| { | |
| index += hash2; | |
| if (index >= size) | |
| index -= size; | |
| entry = htab->entries[index]; | |
| if (entry == HTAB_EMPTY_ENTRY) | |
| goto empty_entry; | |
| else if (entry == HTAB_DELETED_ENTRY) | |
| { | |
| if (!first_deleted_slot) | |
| first_deleted_slot = &htab->entries[index]; | |
| } | |
| else if (htab_eq (entry, element)) | |
| return &htab->entries[index]; | |
| } | |
| empty_entry: | |
| if (insert == NO_INSERT) | |
| return NULL; | |
| if (first_deleted_slot) | |
| { | |
| htab->n_deleted--; | |
| *first_deleted_slot = HTAB_EMPTY_ENTRY; | |
| return first_deleted_slot; | |
| } | |
| htab->n_elements++; | |
| return &htab->entries[index]; | |
| } | |
| /* This function clears a specified slot in a hash table. It is | |
| useful when you've already done the lookup and don't want to do it | |
| again. */ | |
| static inline void | |
| htab_clear_slot (htab_t htab, hash_entry_type *slot) | |
| { | |
| if (slot < htab->entries || slot >= htab->entries + htab_size (htab) | |
| || *slot == HTAB_EMPTY_ENTRY || *slot == HTAB_DELETED_ENTRY) | |
| abort (); | |
| *slot = HTAB_DELETED_ENTRY; | |
| htab->n_deleted++; | |
| } | |
| /* Returns a hash code for pointer P. Simplified version of evahash */ | |
| static inline hashval_t | |
| hash_pointer (const void *p) | |
| { | |
| uintptr_t v = (uintptr_t) p; | |
| if (sizeof (v) > sizeof (hashval_t)) | |
| v ^= v >> (sizeof (uintptr_t) / 2 * __CHAR_BIT__); | |
| return v; | |
| } |