From 82eb1dac163cb4aef8a2e4ebad542378f4e28dca Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 16 Feb 2018 16:52:09 -0800 Subject: [PATCH] Flesh out other bit ops some more for 128bit as well --- src/hb-private.hh | 165 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 126 insertions(+), 39 deletions(-) diff --git a/src/hb-private.hh b/src/hb-private.hh index d9cacbe01..7c2de1522 100644 --- a/src/hb-private.hh +++ b/src/hb-private.hh @@ -322,102 +322,189 @@ static_assert ((sizeof (hb_var_int_t) == 4), ""); typedef const struct _hb_void_t *hb_void_t; #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 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 (sizeof (unsigned int) >= sizeof (mask)) - return __builtin_popcount (mask); + if (sizeof (T) <= sizeof (unsigned int)) + return __builtin_popcount (v); - if (sizeof (unsigned long) >= sizeof (mask)) - return __builtin_popcountl (mask); + if (sizeof (T) <= sizeof (unsigned long)) + return __builtin_popcountl (v); - if (sizeof (unsigned long long) >= sizeof (mask)) - return __builtin_popcountll (mask); + if (sizeof (T) <= sizeof (unsigned long long)) + return __builtin_popcountll (v); #endif if (sizeof (T) <= 4) { /* "HACKMEM 169" */ uint32_t y; - y = (mask >> 1) &033333333333; - y = mask - y - ((y >>1) & 033333333333); + y = (v >> 1) &033333333333; + y = v - y - ((y >>1) & 033333333333); return (((y + (y >> 3)) & 030707070707) % 077); } if (sizeof (T) == 8) { unsigned int shift = 32; - return _hb_popcount ((uint32_t) mask) + _hb_popcount ((uint32_t) (mask >> shift)); + return _hb_popcount ((uint32_t) v) + _hb_popcount ((uint32_t) (v >> shift)); } if (sizeof (T) == 16) { unsigned int shift = 64; - return _hb_popcount ((uint64_t) mask) + _hb_popcount ((uint64_t) (mask >> shift)); + return _hb_popcount ((uint64_t) v) + _hb_popcount ((uint64_t) (v >> shift)); } - unsigned int count = 0; - while (mask) - { - count += _hb_popcount ((uint64_t) mask); - unsigned int shift = 64; - mask = (T) (mask >> shift); - } + assert (0); } /* Returns the number of bits needed to store number */ +template 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__) - 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 #if defined(_MSC_VER) || defined(__MINGW32__) + if (sizeof (T) <= sizeof (unsigned int)) { unsigned long where; - _BitScanReverse (&where, number); + _BitScanReverse (&where, v); return 1 + where; } +# if _WIN64 + if (sizeof (T) <= 8) + { + unsigned long where; + _BitScanReverse64 (&where, v); + return 1 + where; + } +# endif #endif - unsigned int n_bits = 0; - while (number) { - n_bits++; - number >>= 1; + if (sizeof (T) <= 4) + { + /* "bithacks" */ + 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) v >> shift) + shift : + _hb_bit_storage ((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 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__) - 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 #if defined(_MSC_VER) || defined(__MINGW32__) + if (sizeof (T) <= sizeof (unsigned int)) { unsigned long where; - _BitScanForward (&where, number); - return where; + _BitScanForward (&where, v); + return 1 + where; } +# if _WIN64 + if (sizeof (T) <= 8) + { + unsigned long where; + _BitScanForward64 (&where, v); + return 1 + where; + } +# endif #endif - unsigned int n_bits = 0; - while (!(number & 1)) { - n_bits++; - number >>= 1; + if (sizeof (T) <= 4) + { + /* "bithacks" */ + 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) v) : + _hb_bit_storage ((uint64_t) v >> shift) + shift; + } + + assert (0); } static inline bool