diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -672,7 +672,7 @@ #include #endif]) -AC_CHECK_DECLS([__builtin_clz, __builtin_clzl, __builtin_clzll]) +AC_CHECK_DECLS([__builtin_clz, __builtin_clzl, __builtin_clzll, __builtin_popcount]) dnl Check for mallopt(M_ARENA_MAX) (to set glibc arenas) AC_MSG_CHECKING(for mallopt M_ARENA_MAX) diff --git a/src/avalanche.h b/src/avalanche.h --- a/src/avalanche.h +++ b/src/avalanche.h @@ -55,24 +55,6 @@ // score. uint16_t confidence; - /** - * Return the number of bits set in an integer value. - * TODO: There are compiler intrinsics to do that, but we'd need to get them - * detected so this will do for now. - */ - static uint32_t countBits(uint32_t value) { - uint32_t count = 0; - while (value) { - // If the value is non zero, then at least one bit is set. - count++; - - // Clear the rightmost bit set. - value &= (value - 1); - } - - return count; - } - public: VoteRecord(bool accepted) : votes(0xaaaa), confidence(accepted) {} @@ -87,29 +69,7 @@ * Register a new vote for an item and update confidence accordingly. * Returns true if the acceptance or finalization state changed. */ - bool registerVote(bool vote) { - votes = (votes << 1) | vote; - - auto bits = countBits(votes & 0xff); - bool yes = bits > 6; - bool no = bits < 2; - if (!yes && !no) { - // The vote is inconclusive. - return false; - } - - if (isAccepted() == yes) { - // If the vote is in agreement with our internal status, increase - // confidence. - confidence += 2; - return getConfidence() == AVALANCHE_FINALIZATION_SCORE; - } - - // The vote did not agree with our internal state, in that case, reset - // confidence. - confidence = yes; - return true; - } + bool registerVote(bool vote); }; class AvalancheVote { diff --git a/src/avalanche.cpp b/src/avalanche.cpp --- a/src/avalanche.cpp +++ b/src/avalanche.cpp @@ -5,6 +5,7 @@ #include "avalanche.h" #include "chain.h" +#include "config/bitcoin-config.h" #include "netmessagemaker.h" #include "scheduler.h" #include "validation.h" @@ -13,6 +14,47 @@ #include +static uint32_t countBits(uint32_t v) { +#if HAVE_DECL___BUILTIN_POPCOUNT + return __builtin_popcount(v); +#else + /** + * This computes the number of bits set in each group of 8bits then uses a + * multiplication to sum all of them in the 8 most significant bits and + * return these. + * More detailed explaination can be found at + * https://www.playingwithpointers.com/blog/swar.html + */ + v = v - ((v >> 1) & 0x55555555); + v = (v & 0x33333333) + ((v >> 2) & 0x33333333); + return (((v + (v >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; +#endif +} + +bool VoteRecord::registerVote(bool vote) { + votes = (votes << 1) | vote; + + auto bits = countBits(votes & 0xff); + bool yes = bits > 6; + bool no = bits < 2; + if (!yes && !no) { + // The vote is inconclusive. + return false; + } + + if (isAccepted() == yes) { + // If the vote is in agreement with our internal status, increase + // confidence. + confidence += 2; + return getConfidence() == AVALANCHE_FINALIZATION_SCORE; + } + + // The vote did not agree with our internal state, in that case, reset + // confidence. + confidence = yes; + return true; +} + static bool IsWorthPolling(const CBlockIndex *pindex) { AssertLockHeld(cs_main); diff --git a/src/config/CMakeLists.txt b/src/config/CMakeLists.txt --- a/src/config/CMakeLists.txt +++ b/src/config/CMakeLists.txt @@ -110,6 +110,7 @@ check_builtin_exist(__builtin_clz HAVE_DECL___BUILTIN_CLZ) check_builtin_exist(__builtin_clzl HAVE_DECL___BUILTIN_CLZL) check_builtin_exist(__builtin_clzll HAVE_DECL___BUILTIN_CLZLL) +check_builtin_exist(__builtin_popcount HAVE_DECL___BUILTIN_POPCOUNT) # Memory management capabilities check_symbol_exists(M_ARENA_MAX "malloc.h" HAVE_MALLOPT_ARENA_MAX) diff --git a/src/config/bitcoin-config.h.cmake.in b/src/config/bitcoin-config.h.cmake.in --- a/src/config/bitcoin-config.h.cmake.in +++ b/src/config/bitcoin-config.h.cmake.in @@ -44,6 +44,7 @@ #cmakedefine HAVE_DECL___BUILTIN_CLZ 1 #cmakedefine HAVE_DECL___BUILTIN_CLZL 1 #cmakedefine HAVE_DECL___BUILTIN_CLZLL 1 +#cmakedefine HAVE_DECL___BUILTIN_POPCOUNT 1 #cmakedefine HAVE_MALLOPT_ARENA_MAX 1 #cmakedefine HAVE_MALLOC_INFO 1