Flesh out other bit ops some more for 128bit as well

This commit is contained in:
Behdad Esfahbod 2018-02-16 16:52:09 -08:00
parent 864a2dddae
commit 82eb1dac16
1 changed files with 126 additions and 39 deletions

View File

@ -322,102 +322,189 @@ static_assert ((sizeof (hb_var_int_t) == 4), "");
typedef const struct _hb_void_t *hb_void_t; typedef const struct _hb_void_t *hb_void_t;
#define HB_VOID ((const _hb_void_t *) nullptr) #define HB_VOID ((const _hb_void_t *) nullptr)
/* Return the number of 1 bits in mask. */ /* Return the number of 1 bits in v. */
template <typename T> template <typename T>
static inline HB_CONST_FUNC unsigned int static inline HB_CONST_FUNC unsigned int
_hb_popcount (T mask) _hb_popcount (T v)
{ {
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) && defined(__OPTIMIZE__) #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) && defined(__OPTIMIZE__)
if (sizeof (unsigned int) >= sizeof (mask)) if (sizeof (T) <= sizeof (unsigned int))
return __builtin_popcount (mask); return __builtin_popcount (v);
if (sizeof (unsigned long) >= sizeof (mask)) if (sizeof (T) <= sizeof (unsigned long))
return __builtin_popcountl (mask); return __builtin_popcountl (v);
if (sizeof (unsigned long long) >= sizeof (mask)) if (sizeof (T) <= sizeof (unsigned long long))
return __builtin_popcountll (mask); return __builtin_popcountll (v);
#endif #endif
if (sizeof (T) <= 4) if (sizeof (T) <= 4)
{ {
/* "HACKMEM 169" */ /* "HACKMEM 169" */
uint32_t y; uint32_t y;
y = (mask >> 1) &033333333333; y = (v >> 1) &033333333333;
y = mask - y - ((y >>1) & 033333333333); y = v - y - ((y >>1) & 033333333333);
return (((y + (y >> 3)) & 030707070707) % 077); return (((y + (y >> 3)) & 030707070707) % 077);
} }
if (sizeof (T) == 8) if (sizeof (T) == 8)
{ {
unsigned int shift = 32; unsigned int shift = 32;
return _hb_popcount<uint32_t> ((uint32_t) mask) + _hb_popcount ((uint32_t) (mask >> shift)); return _hb_popcount<uint32_t> ((uint32_t) v) + _hb_popcount ((uint32_t) (v >> shift));
} }
if (sizeof (T) == 16) if (sizeof (T) == 16)
{ {
unsigned int shift = 64; unsigned int shift = 64;
return _hb_popcount<uint64_t> ((uint64_t) mask) + _hb_popcount ((uint64_t) (mask >> shift)); return _hb_popcount<uint64_t> ((uint64_t) v) + _hb_popcount ((uint64_t) (v >> shift));
} }
unsigned int count = 0; assert (0);
while (mask)
{
count += _hb_popcount<uint64_t> ((uint64_t) mask);
unsigned int shift = 64;
mask = (T) (mask >> shift);
}
} }
/* Returns the number of bits needed to store number */ /* Returns the number of bits needed to store number */
template <typename T>
static inline HB_CONST_FUNC unsigned int static inline HB_CONST_FUNC unsigned int
_hb_bit_storage (unsigned int number) _hb_bit_storage (T v)
{ {
if (unlikely (!number)) return 0; if (unlikely (!v)) return 0;
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__) #if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
return sizeof (unsigned int) * 8 - __builtin_clz (number); if (sizeof (T) <= sizeof (unsigned int))
return sizeof (unsigned int) * 8 - __builtin_clz (v);
if (sizeof (T) <= sizeof (unsigned long))
return sizeof (unsigned int) * 8 - __builtin_clzl (v);
if (sizeof (T) <= sizeof (unsigned long long))
return sizeof (unsigned int) * 8 - __builtin_clzll (v);
#endif #endif
#if defined(_MSC_VER) || defined(__MINGW32__) #if defined(_MSC_VER) || defined(__MINGW32__)
if (sizeof (T) <= sizeof (unsigned int))
{ {
unsigned long where; unsigned long where;
_BitScanReverse (&where, number); _BitScanReverse (&where, v);
return 1 + where; return 1 + where;
} }
# if _WIN64
if (sizeof (T) <= 8)
{
unsigned long where;
_BitScanReverse64 (&where, v);
return 1 + where;
}
# endif
#endif #endif
unsigned int n_bits = 0; if (sizeof (T) <= 4)
while (number) { {
n_bits++; /* "bithacks" */
number >>= 1; const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
const unsigned int S[] = {1, 2, 4, 8, 16};
unsigned int r = 0;
for (int i = 4; i >= 0; i--)
if (v & b[i])
{
v >>= S[i];
r |= S[i];
}
return r;
} }
return n_bits; if (sizeof (T) <= 8)
{
/* "bithacks" */
const uint64_t b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000, 0xFFFFFFFF00000000};
const unsigned int S[] = {1, 2, 4, 8, 16, 32};
unsigned int r = 0;
for (int i = 5; i >= 0; i--)
if (v & b[i])
{
v >>= S[i];
r |= S[i];
}
return r;
}
if (sizeof (T) == 16)
{
unsigned int shift = 64;
return (v >> shift) ? _hb_bit_storage<uint64_t> ((uint64_t) v >> shift) + shift :
_hb_bit_storage<uint64_t> ((uint64_t) v);
}
assert (0);
} }
/* Returns the number of zero bits in the least significant side of number */ /* Returns the number of zero bits in the least significant side of v */
template <typename T>
static inline HB_CONST_FUNC unsigned int static inline HB_CONST_FUNC unsigned int
_hb_ctz (unsigned int number) _hb_ctz (T v)
{ {
if (unlikely (!number)) return 0; if (unlikely (!v)) return 0;
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__) #if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
return __builtin_ctz (number); if (sizeof (T) <= sizeof (unsigned int))
return __builtin_ctz (v);
if (sizeof (T) <= sizeof (unsigned long))
return __builtin_ctzl (v);
if (sizeof (T) <= sizeof (unsigned long long))
return __builtin_ctzll (v);
#endif #endif
#if defined(_MSC_VER) || defined(__MINGW32__) #if defined(_MSC_VER) || defined(__MINGW32__)
if (sizeof (T) <= sizeof (unsigned int))
{ {
unsigned long where; unsigned long where;
_BitScanForward (&where, number); _BitScanForward (&where, v);
return where; return 1 + where;
} }
# if _WIN64
if (sizeof (T) <= 8)
{
unsigned long where;
_BitScanForward64 (&where, v);
return 1 + where;
}
# endif
#endif #endif
unsigned int n_bits = 0; if (sizeof (T) <= 4)
while (!(number & 1)) { {
n_bits++; /* "bithacks" */
number >>= 1; unsigned int c = 32;
v &= -signed(v);
if (v) c--;
if (v & 0x0000FFFF) c -= 16;
if (v & 0x00FF00FF) c -= 8;
if (v & 0x0F0F0F0F) c -= 4;
if (v & 0x33333333) c -= 2;
if (v & 0x55555555) c -= 1;
return c;
} }
return n_bits; if (sizeof (T) <= 8)
{
/* "bithacks" */
unsigned int c = 64;
v &= -signed(v);
if (v) c--;
if (v & 0x00000000FFFFFFFF) c -= 32;
if (v & 0x0000FFFF0000FFFF) c -= 16;
if (v & 0x00FF00FF00FF00FF) c -= 8;
if (v & 0x0F0F0F0F0F0F0F0F) c -= 4;
if (v & 0x3333333333333333) c -= 2;
if (v & 0x5555555555555555) c -= 1;
return c;
}
if (sizeof (T) == 16)
{
unsigned int shift = 64;
return (uint64_t) v ? _hb_bit_storage<uint64_t> ((uint64_t) v) :
_hb_bit_storage<uint64_t> ((uint64_t) v >> shift) + shift;
}
assert (0);
} }
static inline bool static inline bool