diff --git a/CMakeLists.txt b/CMakeLists.txt index 625a434..e552f7b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -142,6 +142,19 @@ if (HAVE_PTHREAD_CANCEL) add_definitions(/DHAVE_PTHREAD_CANCEL) endif() +include(CheckCXXSourceCompiles) + +check_cxx_source_compiles("int main(){ return __builtin_clzll(1);}" HAVE_BUILTIN_CLZLL) +check_cxx_source_compiles("#include \n#pragma intrinsic(_BitScanReverse64)\nint main(){unsigned long r;_BitScanReverse64(&r,1);return r;}" HAVE_BITSCANREVERSE64) + +if (HAVE_BUILTIN_CLZLL) + add_definitions(/DHAVE_BUILTIN_CLZLL) +endif() + +if (HAVE_BITSCANREVERSE64) + add_definitions(/DHAVE_BITSCANREVERSE64) +endif() + add_executable(${CMAKE_PROJECT_NAME} ${HEADERS} ${SOURCES}) if (STATIC_BINARY) diff --git a/src/stratum_server.cpp b/src/stratum_server.cpp index 5d18564..d14a190 100644 --- a/src/stratum_server.cpp +++ b/src/stratum_server.cpp @@ -562,19 +562,18 @@ enum HashMaxValue : uint64_t { value = hash_uncompress(std::numeric_limits::max()) }; -static constexpr FORCEINLINE uint16_t hash_compress(uint64_t h) +static FORCEINLINE uint16_t hash_compress(uint64_t h) { - if (h > HashMaxValue::value) { - h = HashMaxValue::value; + if (h <= HashValue::mask) { + return static_cast(h); } - uint64_t shift = 0; - while (h > HashValue::mask) { - h >>= 1; - shift += (1 << HashValue::bits); + if (h >= HashMaxValue::value) { + return std::numeric_limits::max(); } - return static_cast(shift | h); + const uint64_t shift = bsr(h) - (HashValue::bits - 1); + return static_cast((shift << HashValue::bits) | (h >> shift)); } } diff --git a/src/util.cpp b/src/util.cpp index 7b261a3..b96fe8d 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -384,4 +384,43 @@ bool resolve_host(std::string& host, bool& is_v6) RandomDeviceSeed RandomDeviceSeed::instance; +struct BSR8 +{ + uint8_t data[256]; + + static constexpr BSR8 init() { + BSR8 result = { 55 }; + + for (int i = 1; i < 256; ++i) { + int x = i; + result.data[i] = 63; + while (x < 0x80) { + --result.data[i]; + x <<= 1; + } + } + + return result; + } +}; + +static constexpr BSR8 bsr8_table = BSR8::init(); + +NOINLINE uint64_t bsr_reference(uint64_t x) +{ + uint32_t y = static_cast(x); + + uint64_t n0 = (x == y) ? 0 : 32; + y = static_cast(x >> n0); + n0 ^= 32; + + const uint64_t n1 = (y & 0xFFFF0000UL) ? 0 : 16; + y <<= n1; + + const uint64_t n2 = (y & 0xFF000000UL) ? 0 : 8; + y <<= n2; + + return bsr8_table.data[y >> 24] - n0 - n1 - n2; +} + } // namespace p2pool diff --git a/src/util.h b/src/util.h index 453496f..7a95874 100644 --- a/src/util.h +++ b/src/util.h @@ -203,6 +203,22 @@ FORCEINLINE uint64_t seconds_since_epoch() return duration_cast(steady_clock::now().time_since_epoch()).count(); } +uint64_t bsr_reference(uint64_t x); + +#ifdef HAVE_BUILTIN_CLZLL +#define bsr(x) (63 - __builtin_clzll(x)) +#elif defined HAVE_BITSCANREVERSE64 +#pragma intrinsic(_BitScanReverse64) +FORCEINLINE uint64_t bsr(uint64_t x) +{ + unsigned long index; + _BitScanReverse64(&index, x); + return index; +} +#else +#define bsr bsr_reference +#endif + } // namespace p2pool namespace robin_hood { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9f3fc54..295097d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -74,7 +74,7 @@ set(SOURCES src/keccak_tests.cpp src/main.cpp src/pool_block_tests.cpp - src/varint_tests.cpp + src/util_tests.cpp src/wallet_tests.cpp ../external/src/cryptonote/crypto-ops-data.c ../external/src/cryptonote/crypto-ops.c @@ -160,6 +160,19 @@ endif() add_definitions(/DZMQ_STATIC /DP2POOL_LOG_DISABLE) +include(CheckCXXSourceCompiles) + +check_cxx_source_compiles("int main(){ return __builtin_clzll(1);}" HAVE_BUILTIN_CLZLL) +check_cxx_source_compiles("#include \n#pragma intrinsic(_BitScanReverse64)\nint main(){unsigned long r;_BitScanReverse64(&r,1);return r;}" HAVE_BITSCANREVERSE64) + +if (HAVE_BUILTIN_CLZLL) + add_definitions(/DHAVE_BUILTIN_CLZLL) +endif() + +if (HAVE_BITSCANREVERSE64) + add_definitions(/DHAVE_BITSCANREVERSE64) +endif() + add_executable(${CMAKE_PROJECT_NAME} ${HEADERS} ${SOURCES}) target_link_libraries(${CMAKE_PROJECT_NAME} debug ${ZMQ_LIBRARY_DEBUG} debug ${UV_LIBRARY_DEBUG} optimized ${ZMQ_LIBRARY} optimized ${UV_LIBRARY} ${LIBS}) add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_SOURCE_DIR}/src/crypto_tests.txt" $) diff --git a/tests/src/varint_tests.cpp b/tests/src/util_tests.cpp similarity index 94% rename from tests/src/varint_tests.cpp rename to tests/src/util_tests.cpp index 8ed5815..9e572b3 100644 --- a/tests/src/varint_tests.cpp +++ b/tests/src/util_tests.cpp @@ -21,7 +21,7 @@ namespace p2pool { -TEST(varint, read_write) +TEST(util, varint) { std::vector v; v.reserve(16); @@ -82,4 +82,12 @@ TEST(varint, read_write) ASSERT_EQ(readVarint(buf2, buf2 + 1, check), nullptr); } +TEST(util, bsr) +{ + for (uint64_t i = 0, x = 1; i <= 63; ++i, x <<= 1) { + ASSERT_EQ(bsr(x), i); + ASSERT_EQ(bsr_reference(x), i); + } +} + }