diff --git a/m-core.h b/m-core.h index 14451cfd..6bc273dc 100644 --- a/m-core.h +++ b/m-core.h @@ -1277,18 +1277,38 @@ static inline uint64_t m_core_roundpow2(uint64_t v) /* Return the count leading zero of the argument */ #if defined(__GNUC__) && (__GNUC__*100 + __GNUC_MINOR__) >= 304 -static inline unsigned int m_core_clz(unsigned long limb) +static inline unsigned int m_core_clz(uint32_t limb) { - return M_UNLIKELY (limb == 0) ? sizeof(unsigned long)*CHAR_BIT : __builtin_clzl(limb); + return M_UNLIKELY (limb == 0) ? sizeof(uint32_t)*CHAR_BIT : __builtin_clzl(limb) - (sizeof(unsigned long) - sizeof(uint32_t)) * CHAR_BIT; +} +static inline unsigned int m_core_clz64(uint64_t limb) +{ + return M_UNLIKELY (limb == 0ULL) ? sizeof (uint64_t)*CHAR_BIT : __builtin_clzll(limb) - (sizeof (unsigned long long) - sizeof (uint64_t)) * CHAR_BIT; } #else #define M_CORE_CLZ_TAB "\010\07\06\06\05\05\05\05\04\04\04\04\04\04\04\04\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00" -static inline unsigned int m_core_clz(unsigned long limb) +static inline unsigned int m_core_clz(uint32_t limb) +{ + unsigned int shift = 0; + /* This code should be branchless on most targets */ + /* Compute shift so that, it is + + -3 if the highest 24 bits are clear, + + -2 for the highest 16 bits, + + -1 for the highest 8 bits, + + 0 otherwise */ + shift = -(limb < 0x1000000UL); + shift -= (limb < 0x10000UL); + shift -= (limb < 0x100UL); + shift = shift*8 + 24; + shift = 24 - shift + M_CORE_CLZ_TAB[limb >> shift ]; + return shift; +} + +static inline unsigned int m_core_clz64(uint64_t limb) { unsigned int shift = 0; /* This code should be branchless on most targets */ -#if ULONG_MAX == 18446744073709551615UL /* Compute shift so that, it is + -7 if the highest 56 bits are clear, + -6 for the highest 48 bits, @@ -1307,20 +1327,6 @@ static inline unsigned int m_core_clz(unsigned long limb) shift -= (limb < 0x100UL); shift = shift*8 + 56; shift = 56 - shift + M_CORE_CLZ_TAB[limb >> shift ]; -#elif ULONG_MAX == 4294967295UL - /* Compute shift so that, it is - + -3 if the highest 24 bits are clear, - + -2 for the highest 16 bits, - + -1 for the highest 8 bits, - + 0 otherwise */ - shift = -(limb < 0x1000000UL); - shift -= (limb < 0x10000UL); - shift -= (limb < 0x100UL); - shift = shift*8 + 24; - shift = 24 - shift + M_CORE_CLZ_TAB[limb >> shift ]; -#else -# error Unkown size for unsigned long. Please create a bug report and report the ULONG_MAX value. -#endif return shift; } #endif diff --git a/m-genint.h b/m-genint.h index aa87e867..0194be62 100644 --- a/m-genint.h +++ b/m-genint.h @@ -122,7 +122,7 @@ static inline size_t genint_pop(genint_t s) // While master is not full while ((master >> GENINT_ABA_CPT) != s->mask_master) { // Let's get the index i of the first not full limb according to master. - unsigned int i = m_core_clz(~master); + unsigned int i = m_core_clz64(~master); // Let's compute the mask of this limb representing the limb as being full genint_limb_t mask = s->mask0; mask = (i == s->max) ? mask : -GENINT_ONE; @@ -134,7 +134,7 @@ static inline size_t genint_pop(genint_t s) if (M_UNLIKELY (org == mask)) goto next_element; // At least one bit is free in the limb. Find one. - bit = GENINT_LIMBSIZE - 1 - m_core_clz(~org); + bit = GENINT_LIMBSIZE - 1 - m_core_clz64(~org); assert ((org & (GENINT_ONE<n); // Set the integer as being used.