diff --git a/configure.ac b/configure.ac index d8c38fe29..02a4a8973 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) @@ -75,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..daa496e98 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 @@ -322,72 +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_popcount32 (uint32_t mask) +_hb_popcount (T v) { -#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 (T) <= sizeof (unsigned int)) + return __builtin_popcount (v); + + if (sizeof (T) <= sizeof (unsigned long)) + return __builtin_popcountl (v); + + if (sizeof (T) <= sizeof (unsigned long long)) + return __builtin_popcountll (v); #endif + + if (sizeof (T) <= 4) + { + /* "HACKMEM 169" */ + uint32_t y; + 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) v) + _hb_popcount ((uint32_t) (v >> shift)); + } + + if (sizeof (T) == 16) + { + unsigned int shift = 64; + return _hb_popcount ((uint64_t) v) + _hb_popcount ((uint64_t) (v >> shift)); + } + + assert (0); } -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 */ +template static inline HB_CONST_FUNC unsigned int -_hb_bit_storage (unsigned int number) +_hb_bit_storage (T v) { + if (unlikely (!v)) 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 - unsigned int n_bits = 0; - while (number) { - n_bits++; - number >>= 1; - } - return n_bits; + if (sizeof (T) <= sizeof (unsigned int)) + return sizeof (unsigned int) * 8 - __builtin_clz (v); + + if (sizeof (T) <= sizeof (unsigned long)) + return sizeof (unsigned long) * 8 - __builtin_clzl (v); + + if (sizeof (T) <= sizeof (unsigned long long)) + return sizeof (unsigned long long) * 8 - __builtin_clzll (v); #endif + +#if defined(_MSC_VER) || defined(__MINGW32__) + if (sizeof (T) <= sizeof (unsigned int)) + { + unsigned long where; + _BitScanReverse (&where, v); + return 1 + where; + } +# if _WIN64 + if (sizeof (T) <= 8) + { + unsigned long where; + _BitScanReverse64 (&where, v); + return 1 + where; + } +# endif +#endif + + 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 + 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 = 0; + for (int i = 5; i >= 0; i--) + if (v & b[i]) + { + v >>= S[i]; + r |= S[i]; + } + return r + 1; + } + 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 (!v)) return 0; + #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; - while (!(number & 1)) { - n_bits++; - number >>= 1; - } - return n_bits; + 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, v); + return where; + } +# if _WIN64 + if (sizeof (T) <= 8) + { + unsigned long where; + _BitScanForward64 (&where, v); + return where; + } +# endif +#endif + + if (sizeof (T) <= 4) + { + /* "bithacks" */ + unsigned int c = 32; + v &= - (int32_t) 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; + } + if (sizeof (T) <= 8) + { + /* "bithacks" */ + unsigned int c = 64; + v &= - (int64_t) (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 diff --git a/src/hb-set-private.hh b/src/hb-set-private.hh index 0c73d32dc..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,52 +131,39 @@ 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; } - 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, ""); + 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". */ @@ -192,6 +174,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; diff --git a/test/api/hb-subset-test.h b/test/api/hb-subset-test.h index e86256747..49e5db480 100644 --- a/test/api/hb-subset-test.h +++ b/test/api/hb-subset-test.h @@ -86,7 +86,7 @@ hb_subset_test_open_font (const char *font_path) return face; } g_assert (false); - return NULL; + return NULL; /* Shut up, compiler! */ } static inline hb_face_t * @@ -115,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)