This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [rfc] division by multiplicative inverse in hashtab.c
I believe I've taken care of all of the comments I recieved.
Committed.
r~
Index: include/hashtab.h
===================================================================
RCS file: /cvs/gcc/gcc/include/hashtab.h,v
retrieving revision 1.21
diff -c -p -d -r1.21 hashtab.h
*** include/hashtab.h 13 Apr 2004 14:48:56 -0000 1.21
--- include/hashtab.h 22 Apr 2004 17:27:17 -0000
***************
*** 1,5 ****
/* An expandable hash tables datatype.
! Copyright (C) 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
Contributed by Vladimir Makarov (vmakarov@cygnus.com).
This program is free software; you can redistribute it and/or modify
--- 1,5 ----
/* An expandable hash tables datatype.
! Copyright (C) 1999, 2000, 2002, 2003, 2004 Free Software Foundation, Inc.
Contributed by Vladimir Makarov (vmakarov@cygnus.com).
This program is free software; you can redistribute it and/or modify
*************** struct htab GTY(())
*** 126,131 ****
--- 126,135 ----
PTR GTY((skip)) alloc_arg;
htab_alloc_with_arg alloc_with_arg_f;
htab_free_with_arg free_with_arg_f;
+
+ /* Current size (in entries) of the hash table, as an index into the
+ table of primes. */
+ unsigned int size_prime_index;
};
typedef struct htab *htab_t;
Index: libiberty/configure.ac
===================================================================
RCS file: /cvs/gcc/gcc/libiberty/configure.ac,v
retrieving revision 1.4
diff -c -p -d -r1.4 configure.ac
*** libiberty/configure.ac 9 Mar 2004 23:02:47 -0000 1.4
--- libiberty/configure.ac 22 Apr 2004 17:27:17 -0000
*************** AC_SUBST_FILE(host_makefile_frag)
*** 159,171 ****
# It's OK to check for header files. Although the compiler may not be
# able to link anything, it had better be able to at least compile
# something.
! AC_CHECK_HEADERS(sys/file.h sys/param.h limits.h stdlib.h malloc.h string.h unistd.h strings.h sys/time.h time.h sys/resource.h sys/stat.h sys/mman.h fcntl.h alloca.h sys/pstat.h sys/sysmp.h sys/sysinfo.h machine/hal_sysinfo.h sys/table.h sys/sysctl.h sys/systemcfg.h)
AC_HEADER_SYS_WAIT
AC_HEADER_TIME
libiberty_AC_DECLARE_ERRNO
AC_CHECK_TYPE(uintptr_t, unsigned long)
# Given the above check, we always have uintptr_t or a fallback
# definition. So define HAVE_UINTPTR_T in case any imported code
# relies on it.
--- 159,205 ----
# It's OK to check for header files. Although the compiler may not be
# able to link anything, it had better be able to at least compile
# something.
! AC_CHECK_HEADERS(sys/file.h sys/param.h limits.h stdlib.h malloc.h string.h unistd.h strings.h sys/time.h time.h sys/resource.h sys/stat.h sys/mman.h fcntl.h alloca.h sys/pstat.h sys/sysmp.h sys/sysinfo.h machine/hal_sysinfo.h sys/table.h sys/sysctl.h sys/systemcfg.h stdint.h)
AC_HEADER_SYS_WAIT
AC_HEADER_TIME
libiberty_AC_DECLARE_ERRNO
AC_CHECK_TYPE(uintptr_t, unsigned long)
+
+ # Look for a 64-bit type.
+ AC_MSG_CHECKING([for a 64-bit type])
+ AC_CACHE_VAL(liberty_cv_uint64,
+ [AC_TRY_COMPILE(
+ [#ifdef HAVE_STDINT_H
+ #include <stdint.h>
+ #endif],
+ [extern uint64_t foo;],
+ liberty_cv_uint64=uint64_t,
+ [AC_TRY_COMPILE(
+ [#ifdef HAVE_LIMITS_H
+ #include <limits.h>
+ #endif
+ #ifndef CHAR_BIT
+ #define CHAR_BIT 8
+ #endif],
+ [extern char foo[sizeof(long) * CHAR_BIT >= 64 ? 1 : -1];],
+ liberty_cv_uint64="unsigned long",
+ [AC_TRY_COMPILE(
+ [#ifdef HAVE_LIMITS_H
+ #include <limits.h>
+ #endif
+ #ifndef CHAR_BIT
+ #define CHAR_BIT 8
+ #endif],
+ [extern char foo[sizeof(long long) * CHAR_BIT >= 64 ? 1 : -1];],
+ liberty_cv_uint64="unsigned long long", liberty_cv_uint64=none)])])])
+ AC_MSG_RESULT($liberty_cv_uint64)
+ if test "$liberty_cv_uint64" != none; then
+ AC_DEFINE(UNSIGNED_64BIT_TYPE, $liberty_cv_uint64,
+ [Define to an unsigned 64-bit type available in the compiler.])
+ fi
+
# Given the above check, we always have uintptr_t or a fallback
# definition. So define HAVE_UINTPTR_T in case any imported code
# relies on it.
Index: libiberty/hashtab.c
===================================================================
RCS file: /cvs/gcc/gcc/libiberty/hashtab.c,v
retrieving revision 1.40
diff -c -p -d -r1.40 hashtab.c
*** libiberty/hashtab.c 13 Apr 2004 14:48:55 -0000 1.40
--- libiberty/hashtab.c 22 Apr 2004 17:27:17 -0000
***************
*** 1,5 ****
/* An expandable hash tables datatype.
! Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
Contributed by Vladimir Makarov (vmakarov@cygnus.com).
This file is part of the libiberty library.
--- 1,6 ----
/* An expandable hash tables datatype.
! Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
! Free Software Foundation, Inc.
Contributed by Vladimir Makarov (vmakarov@cygnus.com).
This file is part of the libiberty library.
*************** Boston, MA 02111-1307, USA. */
*** 40,59 ****
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
-
#ifdef HAVE_STRING_H
#include <string.h>
#endif
-
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
#include <stdio.h>
#include "libiberty.h"
#include "hashtab.h"
/* This macro defines reserved value for empty table entry. */
#define EMPTY_ENTRY ((PTR) 0)
--- 41,69 ----
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
+ #ifdef HAVE_LIMITS_H
+ #include <limits.h>
+ #endif
+ #ifdef HAVE_STDINT_H
+ #include <stdint.h>
+ #endif
#include <stdio.h>
#include "libiberty.h"
+ #include "ansidecl.h"
#include "hashtab.h"
+ #ifndef CHAR_BIT
+ #define CHAR_BIT 8
+ #endif
+
/* This macro defines reserved value for empty table entry. */
#define EMPTY_ENTRY ((PTR) 0)
*************** Boston, MA 02111-1307, USA. */
*** 63,69 ****
#define DELETED_ENTRY ((PTR) 1)
! static unsigned long higher_prime_number PARAMS ((unsigned long));
static hashval_t hash_pointer PARAMS ((const void *));
static int eq_pointer PARAMS ((const void *, const void *));
static int htab_expand PARAMS ((htab_t));
--- 73,82 ----
#define DELETED_ENTRY ((PTR) 1)
! static unsigned int higher_prime_index PARAMS ((unsigned long));
! static hashval_t htab_mod_1 PARAMS ((hashval_t, hashval_t, hashval_t, int));
! static hashval_t htab_mod PARAMS ((hashval_t, htab_t));
! static hashval_t htab_mod_m2 PARAMS ((hashval_t, htab_t));
static hashval_t hash_pointer PARAMS ((const void *));
static int eq_pointer PARAMS ((const void *, const void *));
static int htab_expand PARAMS ((htab_t));
*************** static PTR *find_empty_slot_for_expand
*** 75,143 ****
htab_hash htab_hash_pointer = hash_pointer;
htab_eq htab_eq_pointer = eq_pointer;
! /* The following function returns a nearest prime number which is
! greater than N, and near a power of two. */
! static unsigned long
! higher_prime_number (n)
! unsigned long n;
{
! /* These are primes that are near, but slightly smaller than, a
! power of two. */
! static const unsigned long primes[] = {
! (unsigned long) 7,
! (unsigned long) 13,
! (unsigned long) 31,
! (unsigned long) 61,
! (unsigned long) 127,
! (unsigned long) 251,
! (unsigned long) 509,
! (unsigned long) 1021,
! (unsigned long) 2039,
! (unsigned long) 4093,
! (unsigned long) 8191,
! (unsigned long) 16381,
! (unsigned long) 32749,
! (unsigned long) 65521,
! (unsigned long) 131071,
! (unsigned long) 262139,
! (unsigned long) 524287,
! (unsigned long) 1048573,
! (unsigned long) 2097143,
! (unsigned long) 4194301,
! (unsigned long) 8388593,
! (unsigned long) 16777213,
! (unsigned long) 33554393,
! (unsigned long) 67108859,
! (unsigned long) 134217689,
! (unsigned long) 268435399,
! (unsigned long) 536870909,
! (unsigned long) 1073741789,
! (unsigned long) 2147483647,
! /* 4294967291L */
! ((unsigned long) 2147483647) + ((unsigned long) 2147483644),
! };
! const unsigned long *low = &primes[0];
! const unsigned long *high = &primes[sizeof(primes) / sizeof(primes[0])];
while (low != high)
{
! const unsigned long *mid = low + (high - low) / 2;
! if (n > *mid)
low = mid + 1;
else
high = mid;
}
/* If we've run out of primes, abort. */
! if (n > *low)
{
fprintf (stderr, "Cannot find prime bigger than %lu\n", n);
abort ();
}
! return *low;
}
/* Returns a hash code for P. */
--- 88,204 ----
htab_hash htab_hash_pointer = hash_pointer;
htab_eq htab_eq_pointer = eq_pointer;
! /* 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, 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
! {
! 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 (n)
! 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)
{
fprintf (stderr, "Cannot find prime bigger than %lu\n", n);
abort ();
}
! return low;
}
/* Returns a hash code for P. */
*************** htab_elements (htab)
*** 177,182 ****
--- 238,273 ----
return htab->n_elements - htab->n_deleted;
}
+ /* Return X % Y. */
+
+ static inline hashval_t
+ htab_mod_1 (x, y, inv, shift)
+ hashval_t x, y, inv;
+ int shift;
+ {
+ /* The multiplicative inverses computed above are for 32-bit types, and
+ requires that we be able to compute a highpart multiply. */
+ #ifdef UNSIGNED_64BIT_TYPE
+ __extension__ typedef UNSIGNED_64BIT_TYPE ull;
+ if (sizeof (hashval_t) * CHAR_BIT <= 32)
+ {
+ 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
+
+ /* 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 (hash, htab)
*** 184,190 ****
hashval_t hash;
htab_t htab;
{
! return hash % htab_size (htab);
}
/* Compute the secondary hash for HASH given HTAB's current size. */
--- 275,282 ----
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. */
*************** htab_mod_m2 (hash, htab)
*** 194,200 ****
hashval_t hash;
htab_t htab;
{
! return 1 + hash % (htab_size (htab) - 2);
}
/* This function creates table with length slightly longer than given
--- 286,293 ----
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);
}
/* This function creates table with length slightly longer than given
*************** htab_create_alloc (size, hash_f, eq_f, d
*** 212,219 ****
htab_free free_f;
{
htab_t result;
- size = higher_prime_number (size);
result = (htab_t) (*alloc_f) (1, sizeof (struct htab));
if (result == NULL)
return NULL;
--- 305,315 ----
htab_free free_f;
{
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) (*alloc_f) (1, sizeof (struct htab));
if (result == NULL)
return NULL;
*************** htab_create_alloc (size, hash_f, eq_f, d
*** 225,230 ****
--- 321,327 ----
return NULL;
}
result->size = size;
+ result->size_prime_index = size_prime_index;
result->hash_f = hash_f;
result->eq_f = eq_f;
result->del_f = del_f;
*************** htab_create_alloc_ex (size, hash_f, eq_f
*** 248,255 ****
htab_free_with_arg free_f;
{
htab_t result;
- size = higher_prime_number (size);
result = (htab_t) (*alloc_f) (alloc_arg, 1, sizeof (struct htab));
if (result == NULL)
return NULL;
--- 345,355 ----
htab_free_with_arg free_f;
{
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) (*alloc_f) (alloc_arg, 1, sizeof (struct htab));
if (result == NULL)
return NULL;
*************** htab_create_alloc_ex (size, hash_f, eq_f
*** 261,266 ****
--- 361,367 ----
return NULL;
}
result->size = size;
+ result->size_prime_index = size_prime_index;
result->hash_f = hash_f;
result->eq_f = eq_f;
result->del_f = del_f;
*************** htab_expand (htab)
*** 412,430 ****
PTR *olimit;
PTR *p;
PTR *nentries;
! size_t nsize;
oentries = htab->entries;
! olimit = oentries + htab->size;
/* Resize only when table after removal of unused elements is either
too full or too empty. */
! if ((htab->n_elements - htab->n_deleted) * 2 > htab->size
! || ((htab->n_elements - htab->n_deleted) * 8 < htab->size
! && htab->size > 32))
! nsize = higher_prime_number ((htab->n_elements - htab->n_deleted) * 2);
else
! nsize = htab->size;
if (htab->alloc_with_arg_f != NULL)
nentries = (PTR *) (*htab->alloc_with_arg_f) (htab->alloc_arg, nsize,
--- 513,539 ----
PTR *olimit;
PTR *p;
PTR *nentries;
! size_t nsize, osize, elts;
! unsigned int oindex, nindex;
oentries = htab->entries;
! oindex = htab->size_prime_index;
! osize = htab->size;
! olimit = oentries + 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))
! {
! nindex = higher_prime_index (elts * 2);
! nsize = prime_tab[nindex].prime;
! }
else
! {
! nindex = oindex;
! nsize = osize;
! }
if (htab->alloc_with_arg_f != NULL)
nentries = (PTR *) (*htab->alloc_with_arg_f) (htab->alloc_arg, nsize,
*************** htab_expand (htab)
*** 435,441 ****
return 0;
htab->entries = nentries;
htab->size = nsize;
!
htab->n_elements -= htab->n_deleted;
htab->n_deleted = 0;
--- 544,550 ----
return 0;
htab->entries = nentries;
htab->size = nsize;
! htab->size_prime_index = nindex;
htab->n_elements -= htab->n_deleted;
htab->n_deleted = 0;