On December 19, 2014 12:48:22 AM CET, Jan Hubicka <hubi...@ucw.cz> wrote: >Hi, >this patch started as experiment moving hash_table_mod1 inline because >it shows >high in streaming profiles and it represents a branch-less code that is >good >to schedule to surrounding instructions. >While looking at hash-tab.h I however noticed that it was not updated >very >well while it was moved from libiberty.h. It still assumes lack of >64bit >integers to be possible and also it uses abort() calls instead of >gcc_asserts. >Fixed thus.
I think for optimal result you want to use GCC_unreachable in the place of the aborts instead. (To get value information for non-checking builds) Richard. > >Bootstrapped/regtested x86_64-linux, also checked that cc1plus binary >shirnks by about 15kb despite the extra inlining. Will commit it >shortly. > >Honza > > * hash-table.h (struct pointer_hash): Fix formating. > (hash_table_higher_prime_index): Declare pure. > (hash_table_mod2, hash_table_mod1, mul_mod): Move inline; > assume that uint64_t always exists. > (hash_table<Descriptor, Allocator, false>): Use gcc_checking_assert. > (hash_table<Descriptor, Allocator, false>::expand ()): Fix formating. > (hash_table<Descriptor, Allocator, false>::clear_slot (value_type >**slot)): > Use checking assert. > * hash-table.c: Remvoe #if 0 code. > (hash_table_higher_prime_index): Use gcc_assert. > (mul_mod, hash-table_mod1, hash_table_mod2): move to hash-table.h > >Index: hash-table.h >=================================================================== >--- hash-table.h (revision 218795) >+++ hash-table.h (working copy) >@@ -282,7 +282,8 @@ struct pointer_hash : typed_noop_remove > > static inline hashval_t hash (const value_type &); > >- static inline bool equal (const value_type &existing, const >compare_type &candidate); >+ static inline bool equal (const value_type &existing, >+ const compare_type &candidate); > }; > > template <typename Type> >@@ -388,9 +389,54 @@ extern struct prime_ent const prime_tab[ > > /* Functions for computing hash table indexes. */ > >-extern unsigned int hash_table_higher_prime_index (unsigned long n); >-extern hashval_t hash_table_mod1 (hashval_t hash, unsigned int index); >-extern hashval_t hash_table_mod2 (hashval_t hash, unsigned int index); >+extern unsigned int hash_table_higher_prime_index (unsigned long n) >+ ATTRIBUTE_PURE; >+ >+/* Return X % Y using multiplicative inverse values INV and SHIFT. >+ >+ The multiplicative inverses computed above are for 32-bit types, >+ and requires that we be able to compute a highpart multiply. >+ >+ FIX: I am not at all convinced that >+ 3 loads, 2 multiplications, 3 shifts, and 3 additions >+ will be faster than >+ 1 load and 1 modulus >+ on modern systems running a compiler. */ >+ >+inline hashval_t >+mul_mod (hashval_t x, hashval_t y, hashval_t inv, int shift) >+{ >+ hashval_t t1, t2, t3, t4, q, r; >+ >+ t1 = ((uint64_t)x * inv) >> 32; >+ t2 = x - t1; >+ t3 = t2 >> 1; >+ t4 = t1 + t3; >+ q = t4 >> shift; >+ r = x - (q * y); >+ >+ return r; >+} >+ >+/* Compute the primary table index for HASH given current prime index. > */ >+ >+inline hashval_t >+hash_table_mod1 (hashval_t hash, unsigned int index) >+{ >+ const struct prime_ent *p = &prime_tab[index]; >+ gcc_checking_assert (sizeof (hashval_t) * CHAR_BIT <= 32); >+ return mul_mod (hash, p->prime, p->inv, p->shift); >+} >+ >+/* Compute the secondary table index for HASH given current prime >index. */ >+ >+inline hashval_t >+hash_table_mod2 (hashval_t hash, unsigned int index) >+{ >+ const struct prime_ent *p = &prime_tab[index]; >+ gcc_checking_assert (sizeof (hashval_t) * CHAR_BIT <= 32); >+ return 1 + mul_mod (hash, p->prime - 2, p->inv_m2, p->shift); >+} > >/* The below is some template meta programming to decide if we should >use the >hash table partial specialization that directly stores value_type >instead of >@@ -748,8 +794,7 @@ hash_table<Descriptor, Allocator, false> > > if (*slot == HTAB_EMPTY_ENTRY) > return slot; >- else if (*slot == HTAB_DELETED_ENTRY) >- abort (); >+ gcc_checking_assert (*slot != HTAB_DELETED_ENTRY); > > hash2 = hash_table_mod2 (hash, m_size_prime_index); > for (;;) >@@ -761,8 +806,7 @@ hash_table<Descriptor, Allocator, false> > slot = m_entries + index; > if (*slot == HTAB_EMPTY_ENTRY) > return slot; >- else if (*slot == HTAB_DELETED_ENTRY) >- abort (); >+ gcc_checking_assert (*slot != HTAB_DELETED_ENTRY); > } > } > >@@ -773,7 +817,7 @@ hash_table<Descriptor, Allocator, false> > table entries is changed. If memory allocation fails, this function > will abort. */ > >- template<typename Descriptor, template<typename Type> class >Allocator> >+template<typename Descriptor, template<typename Type> class Allocator> > void > hash_table<Descriptor, Allocator, false>::expand () > { >@@ -862,9 +906,9 @@ template<typename Descriptor, template<t > void >hash_table<Descriptor, Allocator, false>::clear_slot (value_type >**slot) > { >- if (slot < m_entries || slot >= m_entries + size () >- || *slot == HTAB_EMPTY_ENTRY || *slot == HTAB_DELETED_ENTRY) >- abort (); >+ gcc_checking_assert (!(slot < m_entries || slot >= m_entries + size >() >+ || *slot == HTAB_EMPTY_ENTRY >+ || *slot == HTAB_DELETED_ENTRY)); > > Descriptor::remove (*slot); > >@@ -1317,8 +1361,9 @@ hash_table<Descriptor, Allocator, true> > > if (is_empty (*slot)) > return slot; >- else if (is_deleted (*slot)) >- abort (); >+#ifdef ENABLE_CHECKING >+ gcc_checking_assert (!is_deleted (*slot)); >+#endif > > hash2 = hash_table_mod2 (hash, m_size_prime_index); > for (;;) >@@ -1330,8 +1375,9 @@ hash_table<Descriptor, Allocator, true> > slot = m_entries + index; > if (is_empty (*slot)) > return slot; >- else if (is_deleted (*slot)) >- abort (); >+#ifdef ENABLE_CHECKING >+ gcc_checking_assert (!is_deleted (*slot)); >+#endif > } > } > >@@ -1437,9 +1483,8 @@ template<typename Descriptor, template<t > void > hash_table<Descriptor, Allocator, true>::clear_slot (value_type *slot) > { >- if (slot < m_entries || slot >= m_entries + size () >- || is_empty (*slot) || is_deleted (*slot)) >- abort (); >+ gcc_checking_assert (!(slot < m_entries || slot >= m_entries + size >() >+ || is_empty (*slot) || is_deleted (*slot))); > > Descriptor::remove (*slot); > >Index: hash-table.c >=================================================================== >--- hash-table.c (revision 218795) >+++ hash-table.c (working copy) >@@ -41,39 +41,6 @@ along with GCC; see the file COPYING3. > For the record, here's the function that computed the table; it's a >vastly simplified version of the function of the same name from gcc. >*/ > >-#if 0 >-unsigned int >-ceil_log2 (unsigned int x) >-{ >- int i; >- for (i = 31; i >= 0 ; --i) >- if (x > (1u << i)) >- return i+1; >- abort (); >-} >- >-unsigned int >-choose_multiplier (unsigned int d, unsigned int *mlp, unsigned char >*shiftp) >-{ >- unsigned long long mhigh; >- double nx; >- int lgup, post_shift; >- int pow, pow2; >- int n = 32, precision = 32; >- >- lgup = ceil_log2 (d); >- pow = n + lgup; >- pow2 = n + lgup - precision; >- >- nx = ldexp (1.0, pow) + ldexp (1.0, pow2); >- mhigh = nx / d; >- >- *shiftp = lgup - 1; >- *mlp = mhigh; >- return mhigh >> 32; >-} >-#endif >- > struct prime_ent const prime_tab[] = { > { 7, 0x24924925, 0x9999999b, 2 }, > { 13, 0x3b13b13c, 0x745d1747, 3 }, >@@ -127,67 +94,8 @@ hash_table_higher_prime_index (unsigned > } > > /* If we've run out of primes, abort. */ >- if (n > prime_tab[low].prime) >- { >- fprintf (stderr, "Cannot find prime bigger than %lu\n", n); >- abort (); >- } >+ gcc_assert (n <= prime_tab[low].prime); > > return low; > } > >-/* Return X % Y using multiplicative inverse values INV and SHIFT. >- >- The multiplicative inverses computed above are for 32-bit types, >- and requires that we be able to compute a highpart multiply. >- >- FIX: I am not at all convinced that >- 3 loads, 2 multiplications, 3 shifts, and 3 additions >- will be faster than >- 1 load and 1 modulus >- on modern systems running a compiler. */ >- >-#ifdef UNSIGNED_64BIT_TYPE >-static inline hashval_t >-mul_mod (hashval_t x, hashval_t y, hashval_t inv, int shift) >-{ >- __extension__ typedef UNSIGNED_64BIT_TYPE ull; >- hashval_t t1, t2, t3, t4, q, r; >- >- t1 = ((ull)x * inv) >> 32; >- t2 = x - t1; >- t3 = t2 >> 1; >- t4 = t1 + t3; >- q = t4 >> shift; >- r = x - (q * y); >- >- return r; >-} >-#endif >- >-/* Compute the primary table index for HASH given current prime index. > */ >- >-hashval_t >-hash_table_mod1 (hashval_t hash, unsigned int index) >-{ >- const struct prime_ent *p = &prime_tab[index]; >-#ifdef UNSIGNED_64BIT_TYPE >- if (sizeof (hashval_t) * CHAR_BIT <= 32) >- return mul_mod (hash, p->prime, p->inv, p->shift); >-#endif >- return hash % p->prime; >-} >- >- >-/* Compute the secondary table index for HASH given current prime >index. */ >- >-hashval_t >-hash_table_mod2 (hashval_t hash, unsigned int index) >-{ >- const struct prime_ent *p = &prime_tab[index]; >-#ifdef UNSIGNED_64BIT_TYPE >- if (sizeof (hashval_t) * CHAR_BIT <= 32) >- return 1 + mul_mod (hash, p->prime - 2, p->inv_m2, p->shift); >-#endif >- return 1 + hash % (p->prime - 2); >-}