From 94d32d1b83892ed4f124463cf4322bf74b3e850d Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 16 Feb 2018 15:36:20 -0800 Subject: [PATCH 01/12] Enable C99 if available Hopefully we can now mix-and-match code and declaration in the C test files. --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index d8c38fe29..7dbd553d1 100644 --- a/configure.ac +++ b/configure.ac @@ -20,6 +20,7 @@ LT_INIT([disable-static]) # Check for programs AC_USE_SYSTEM_EXTENSIONS AC_PROG_CC +AC_PROG_CC_C99 AM_PROG_CC_C_O AC_PROG_CXX dnl AX_CXX_COMPILE_STDCXX(11, noext, optional) From 7b5ce7404716a17f91ff86d374c7b76ee7ce3247 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 16 Feb 2018 15:37:22 -0800 Subject: [PATCH 02/12] Fix warnings --- src/hb-ot-os2-table.hh | 2 +- test/api/hb-subset-test.h | 3 ++- test/api/hb-test.h | 9 +++++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/hb-ot-os2-table.hh b/src/hb-ot-os2-table.hh index 18dc4ab07..5f4e2db0d 100644 --- a/src/hb-ot-os2-table.hh +++ b/src/hb-ot-os2-table.hh @@ -78,7 +78,7 @@ struct os2 { hb_codepoint_t min = -1, max = 0; - for (int i = 0; i < codepoints.len; i++) + for (unsigned int i = 0; i < codepoints.len; i++) { hb_codepoint_t cp = codepoints[i]; if (cp < min) diff --git a/test/api/hb-subset-test.h b/test/api/hb-subset-test.h index 12d402d33..49e5db480 100644 --- a/test/api/hb-subset-test.h +++ b/test/api/hb-subset-test.h @@ -86,6 +86,7 @@ hb_subset_test_open_font (const char *font_path) return face; } g_assert (false); + return NULL; /* Shut up, compiler! */ } static inline hb_face_t * @@ -114,7 +115,7 @@ hb_subset_test_check (hb_face_t *expected, { hb_blob_t *expected_blob = hb_face_reference_table (expected, table); hb_blob_t *actual_blob = hb_face_reference_table (actual, table); - hb_test_assert_blob_eq(expected_blob, actual_blob); + hb_test_assert_blobs_equal (expected_blob, actual_blob); hb_blob_destroy (expected_blob); hb_blob_destroy (actual_blob); } diff --git a/test/api/hb-test.h b/test/api/hb-test.h index 48ccc3b28..a88b00c48 100644 --- a/test/api/hb-test.h +++ b/test/api/hb-test.h @@ -160,8 +160,14 @@ typedef void (*hb_test_fixture_func_t) (void); #if !GLIB_CHECK_VERSION(2,30,0) #define g_test_fail() g_error("Test failed") #endif +#ifndef g_assert_true +#define g_assert_true g_assert +#endif +#ifndef g_assert_cmpmem +#define g_assert_cmpmem(m1, l1, m2, l2) g_assert_true (l1 == l2 && memcmp (m1, m2, l1) == 0) +#endif -static inline void hb_test_assert_blob_eq(hb_blob_t *expected_blob, hb_blob_t *actual_blob) +static inline void hb_test_assert_blobs_equal (hb_blob_t *expected_blob, hb_blob_t *actual_blob) { unsigned int expected_length, actual_length; const char *raw_expected = hb_blob_get_data (expected_blob, &expected_length); @@ -170,7 +176,6 @@ static inline void hb_test_assert_blob_eq(hb_blob_t *expected_blob, hb_blob_t *a g_assert_cmpint(0, ==, memcmp(raw_expected, raw_actual, expected_length)); } - static inline void hb_test_add_func (const char *test_path, hb_test_func_t test_func) From 978ace6fbbc828adc20f21591d138f41d8508ebc Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 16 Feb 2018 16:06:17 -0800 Subject: [PATCH 03/12] Improve _hb_popcount() Support 128bit type. --- configure.ac | 3 +- src/hb-ot-layout-gpos-table.hh | 2 +- src/hb-ot-map.cc | 2 +- src/hb-private.hh | 61 ++++++++++++++++++++++------------ 4 files changed, 44 insertions(+), 24 deletions(-) diff --git a/configure.ac b/configure.ac index 7dbd553d1..02a4a8973 100644 --- a/configure.ac +++ b/configure.ac @@ -76,7 +76,8 @@ GTK_DOC_CHECK([1.15],[--flavour no-tmpl]) AM_CONDITIONAL([ENABLE_GTK_DOC], false) ]) -# Functions and headers +# Types, functions, and headers +AC_CHECK_TYPES(unsigned __int128) AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l setlinebuf) AC_CHECK_HEADERS(unistd.h sys/mman.h xlocale.h) diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh index 14ee37131..5b1bc6abd 100644 --- a/src/hb-ot-layout-gpos-table.hh +++ b/src/hb-ot-layout-gpos-table.hh @@ -99,7 +99,7 @@ struct ValueFormat : HBUINT16 #endif inline unsigned int get_len (void) const - { return _hb_popcount32 ((unsigned int) *this); } + { return _hb_popcount ((unsigned int) *this); } inline unsigned int get_size (void) const { return get_len () * Value::static_size; } diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc index 6f07a7e22..54b0ce377 100644 --- a/src/hb-ot-map.cc +++ b/src/hb-ot-map.cc @@ -139,7 +139,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, { static_assert ((!(HB_GLYPH_FLAG_DEFINED & (HB_GLYPH_FLAG_DEFINED + 1))), ""); unsigned int global_bit_mask = HB_GLYPH_FLAG_DEFINED + 1; - unsigned int global_bit_shift = _hb_popcount32 (HB_GLYPH_FLAG_DEFINED); + unsigned int global_bit_shift = _hb_popcount (HB_GLYPH_FLAG_DEFINED); m.global_mask = global_bit_mask; diff --git a/src/hb-private.hh b/src/hb-private.hh index aeed58ae2..f4a31a69b 100644 --- a/src/hb-private.hh +++ b/src/hb-private.hh @@ -323,31 +323,50 @@ 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. */ +template static inline HB_CONST_FUNC unsigned int -_hb_popcount32 (uint32_t mask) +_hb_popcount (T mask) { -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) - return __builtin_popcount (mask); -#else - /* "HACKMEM 169" */ - uint32_t y; - y = (mask >> 1) &033333333333; - y = mask - y - ((y >>1) & 033333333333); - return (((y + (y >> 3)) & 030707070707) % 077); +#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) && defined(__OPTIMIZE__) + if (sizeof (unsigned int) >= sizeof (mask)) + return __builtin_popcount (mask); + + if (sizeof (unsigned long) >= sizeof (mask)) + return __builtin_popcountl (mask); + + if (sizeof (unsigned long long) >= sizeof (mask)) + return __builtin_popcountll (mask); #endif + + if (sizeof (T) <= 4) + { + /* "HACKMEM 169" */ + uint32_t y; + y = (mask >> 1) &033333333333; + y = mask - 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)); + } + + if (sizeof (T) == 16) + { + unsigned int shift = 64; + return _hb_popcount ((uint64_t) mask) + _hb_popcount ((uint64_t) (mask >> shift)); + } + + unsigned int count = 0; + while (mask) + { + count += _hb_popcount ((uint64_t) mask); + unsigned int shift = 64; + mask = (T) (mask >> shift); + } } -static inline HB_CONST_FUNC unsigned int -_hb_popcount64 (uint64_t mask) -{ -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) - if (sizeof (long) >= sizeof (mask)) - return __builtin_popcountl (mask); -#endif - return _hb_popcount32 (mask & 0xFFFFFFFF) + _hb_popcount32 (mask >> 32); -} -template static inline unsigned int _hb_popcount (T mask); -template <> inline unsigned int _hb_popcount (uint32_t mask) { return _hb_popcount32 (mask); } -template <> inline unsigned int _hb_popcount (uint64_t mask) { return _hb_popcount64 (mask); } /* Returns the number of bits needed to store number */ static inline HB_CONST_FUNC unsigned int From 864a2dddae9eb1303c59d0d3717fce307a72a524 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 16 Feb 2018 14:21:40 -0800 Subject: [PATCH 04/12] Clean up bit functions Compile all code-paths possible, to better catch errors. Also enable MSVC ones on mingw which seems to support them. --- src/hb-private.hh | 45 ++++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/src/hb-private.hh b/src/hb-private.hh index f4a31a69b..d9cacbe01 100644 --- a/src/hb-private.hh +++ b/src/hb-private.hh @@ -51,7 +51,7 @@ #include #include -#if defined(_MSC_VER) +#if defined(_MSC_VER) || defined(__MINGW32__) #include #endif @@ -372,41 +372,52 @@ _hb_popcount (T mask) static inline HB_CONST_FUNC unsigned int _hb_bit_storage (unsigned int number) { + if (unlikely (!number)) return 0; + #if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__) - return likely (number) ? (sizeof (unsigned int) * 8 - __builtin_clz (number)) : 0; -#elif defined(_MSC_VER) - unsigned long where; - if (_BitScanReverse (&where, number)) return 1 + where; - return 0; -#else + return sizeof (unsigned int) * 8 - __builtin_clz (number); +#endif + +#if defined(_MSC_VER) || defined(__MINGW32__) + { + unsigned long where; + _BitScanReverse (&where, number); + return 1 + where; + } +#endif + unsigned int n_bits = 0; while (number) { n_bits++; number >>= 1; } return n_bits; -#endif } /* Returns the number of zero bits in the least significant side of number */ static inline HB_CONST_FUNC unsigned int _hb_ctz (unsigned int number) { -#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__) - return likely (number) ? __builtin_ctz (number) : 0; -#elif defined(_MSC_VER) - unsigned long where; - if (_BitScanForward (&where, number)) return where; - return 0; -#else - unsigned int n_bits = 0; if (unlikely (!number)) return 0; + +#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__) + return __builtin_ctz (number); +#endif + +#if defined(_MSC_VER) || defined(__MINGW32__) + { + unsigned long where; + _BitScanForward (&where, number); + return where; + } +#endif + + unsigned int n_bits = 0; while (!(number & 1)) { n_bits++; number >>= 1; } return n_bits; -#endif } static inline bool From 82eb1dac163cb4aef8a2e4ebad542378f4e28dca Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 16 Feb 2018 16:52:09 -0800 Subject: [PATCH 05/12] 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 From 6d5c0bf8b18ed53e8d40dcbae83ec66ed2116843 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 16 Feb 2018 17:33:26 -0800 Subject: [PATCH 06/12] Fix bitops fallback impl --- src/hb-private.hh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hb-private.hh b/src/hb-private.hh index 7c2de1522..a8bc5ed10 100644 --- a/src/hb-private.hh +++ b/src/hb-private.hh @@ -402,7 +402,7 @@ _hb_bit_storage (T v) /* "bithacks" */ const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000}; const unsigned int S[] = {1, 2, 4, 8, 16}; - unsigned int r = 0; + unsigned int r = 1; for (int i = 4; i >= 0; i--) if (v & b[i]) { @@ -416,7 +416,7 @@ _hb_bit_storage (T v) /* "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; + unsigned int r = 1; for (int i = 5; i >= 0; i--) if (v & b[i]) { From d25c3e69e9b0cb9d947e98845b9e3a14ce58e350 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 16 Feb 2018 17:45:09 -0800 Subject: [PATCH 07/12] [set] Readjust parameters --- src/hb-set-private.hh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hb-set-private.hh b/src/hb-set-private.hh index 0c73d32dc..55a529195 100644 --- a/src/hb-set-private.hh +++ b/src/hb-set-private.hh @@ -177,9 +177,8 @@ struct hb_set_t return 0; } - typedef uint32_t elt_t; - static const unsigned int ELT_BITS = sizeof (elt_t) * 8; - static const unsigned int PAGE_BITS = ELT_BITS * ELT_BITS; /* 1024. Use to tune. */ + typedef unsigned long long elt_t; + static const unsigned int PAGE_BITS = 1024; static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, ""); #if 0 && HAVE_VECTOR_SIZE @@ -192,6 +191,7 @@ struct hb_set_t vector_t v; + static const unsigned int ELT_BITS = sizeof (elt_t) * 8; static const unsigned int ELT_MASK = ELT_BITS - 1; static const unsigned int BITS = sizeof (vector_t) * 8; static const unsigned int MASK = BITS - 1; From 6a91a2eb04951f6e33706c2b8e9cd987b429fce9 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 16 Feb 2018 17:49:41 -0800 Subject: [PATCH 08/12] Fix wide bitops implemenetation --- src/hb-private.hh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hb-private.hh b/src/hb-private.hh index a8bc5ed10..c9e5a5ca3 100644 --- a/src/hb-private.hh +++ b/src/hb-private.hh @@ -374,10 +374,10 @@ _hb_bit_storage (T v) return sizeof (unsigned int) * 8 - __builtin_clz (v); if (sizeof (T) <= sizeof (unsigned long)) - return sizeof (unsigned int) * 8 - __builtin_clzl (v); + return sizeof (unsigned long) * 8 - __builtin_clzl (v); if (sizeof (T) <= sizeof (unsigned long long)) - return sizeof (unsigned int) * 8 - __builtin_clzll (v); + return sizeof (unsigned long long) * 8 - __builtin_clzll (v); #endif #if defined(_MSC_VER) || defined(__MINGW32__) From f18b9fbf6583dff72675be7859fc147ec24a0dd2 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 16 Feb 2018 18:14:41 -0800 Subject: [PATCH 09/12] [set] Implement iteration using bitop intrinsics --- src/hb-set-private.hh | 55 +++++++++++++++---------------------------- 1 file changed, 19 insertions(+), 36 deletions(-) diff --git a/src/hb-set-private.hh b/src/hb-set-private.hh index 55a529195..49cd79122 100644 --- a/src/hb-set-private.hh +++ b/src/hb-set-private.hh @@ -109,21 +109,16 @@ struct hb_set_t unsigned int i = m / ELT_BITS; unsigned int j = m & ELT_MASK; - for (; j < ELT_BITS; j++) - if (v[i] & (elt_t (1) << j)) - goto found; - for (i++; i < len (); i++) - if (v[i]) - for (j = 0; j < ELT_BITS; j++) - if (v[i] & (elt_t (1) << j)) - goto found; + const elt_t vv = v[i] & ~((elt_t (1) << j) - 1); + for (const elt_t *p = &vv; i < len (); p = &v[++i]) + if (*p) + { + *codepoint = i * ELT_BITS + elt_get_min (*p); + return true; + } *codepoint = INVALID; return false; - - found: - *codepoint = i * ELT_BITS + j; - return true; } inline bool previous (hb_codepoint_t *codepoint) const { @@ -136,44 +131,29 @@ struct hb_set_t unsigned int i = m / ELT_BITS; unsigned int j = m & ELT_MASK; - for (; (int) j >= 0; j--) - if (v[i] & (elt_t (1) << j)) - goto found; - for (i--; (int) i >= 0; i--) - if (v[i]) - for (j = ELT_BITS - 1; (int) j >= 0; j--) - if (v[i] & (elt_t (1) << j)) - goto found; + const elt_t vv = v[i] & ((elt_t (1) << (j + 1)) - 1); + for (const elt_t *p = &vv; (int) i >= 0; p = &v[--i]) + if (*p) + { + *codepoint = i * ELT_BITS + elt_get_max (*p); + return true; + } *codepoint = INVALID; return false; - - found: - *codepoint = i * ELT_BITS + j; - return true; } inline hb_codepoint_t get_min (void) const { for (unsigned int i = 0; i < len (); i++) if (v[i]) - { - elt_t e = v[i]; - for (unsigned int j = 0; j < ELT_BITS; j++) - if (e & (elt_t (1) << j)) - return i * ELT_BITS + j; - } + return i * ELT_BITS + elt_get_min (v[i]); return INVALID; } inline hb_codepoint_t get_max (void) const { for (int i = len () - 1; i >= 0; i--) if (v[i]) - { - elt_t e = v[i]; - for (int j = ELT_BITS - 1; j >= 0; j--) - if (e & (elt_t (1) << j)) - return i * ELT_BITS + j; - } + return i * ELT_BITS + elt_get_max (v[i]); return 0; } @@ -181,6 +161,9 @@ struct hb_set_t static const unsigned int PAGE_BITS = 1024; static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, ""); + static inline unsigned int elt_get_min (const elt_t &elt) { return _hb_ctz (elt); } + static inline unsigned int elt_get_max (const elt_t &elt) { return _hb_bit_storage (elt) - 1; } + #if 0 && HAVE_VECTOR_SIZE /* The vectorized version does not work with clang as non-const * elt() errs "non-const reference cannot bind to vector element". */ From 4e517ecb6b7c27d4053a6476bb9262858e2567ed Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 16 Feb 2018 18:20:12 -0800 Subject: [PATCH 10/12] Another bitops fallback impl fix --- src/hb-private.hh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hb-private.hh b/src/hb-private.hh index c9e5a5ca3..8461f641b 100644 --- a/src/hb-private.hh +++ b/src/hb-private.hh @@ -402,28 +402,28 @@ _hb_bit_storage (T v) /* "bithacks" */ const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000}; const unsigned int S[] = {1, 2, 4, 8, 16}; - unsigned int r = 1; + unsigned int r = 0; for (int i = 4; i >= 0; i--) if (v & b[i]) { v >>= S[i]; r |= S[i]; } - return r; + return r + 1; } 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 = 1; + unsigned int r = 0; for (int i = 5; i >= 0; i--) if (v & b[i]) { v >>= S[i]; r |= S[i]; } - return r; + return r + 1; } if (sizeof (T) == 16) { From cd11107bb44ac719709e10264e9e6ba6a1cfae0c Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 16 Feb 2018 18:28:58 -0800 Subject: [PATCH 11/12] Another bitops fallback fix I'm confident that all bugs are hashed out now. --- src/hb-private.hh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hb-private.hh b/src/hb-private.hh index 8461f641b..583b56153 100644 --- a/src/hb-private.hh +++ b/src/hb-private.hh @@ -474,7 +474,7 @@ _hb_ctz (T v) { /* "bithacks" */ unsigned int c = 32; - v &= -signed(v); + v &= - (int32_t) v; if (v) c--; if (v & 0x0000FFFF) c -= 16; if (v & 0x00FF00FF) c -= 8; @@ -487,7 +487,7 @@ _hb_ctz (T v) { /* "bithacks" */ unsigned int c = 64; - v &= -signed(v); + v &= - (int64_t) (v); if (v) c--; if (v & 0x00000000FFFFFFFF) c -= 32; if (v & 0x0000FFFF0000FFFF) c -= 16; From 97a71102153d28982297a190739c7d82e76b109e Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 18 Feb 2018 10:50:24 -0800 Subject: [PATCH 12/12] Fix BitScanForward() usage Should fix Win64 bot. --- src/hb-private.hh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hb-private.hh b/src/hb-private.hh index 583b56153..daa496e98 100644 --- a/src/hb-private.hh +++ b/src/hb-private.hh @@ -458,14 +458,14 @@ _hb_ctz (T v) { unsigned long where; _BitScanForward (&where, v); - return 1 + where; + return where; } # if _WIN64 if (sizeof (T) <= 8) { unsigned long where; _BitScanForward64 (&where, v); - return 1 + where; + return where; } # endif #endif