diff --git a/include/dwarfs/compiler.h b/include/dwarfs/compiler.h index 954940e2..a7d53597 100644 --- a/include/dwarfs/compiler.h +++ b/include/dwarfs/compiler.h @@ -28,3 +28,11 @@ #define DWARFS_LIKELY(x) (x) #define DWARFS_UNLIKELY(x) (x) #endif + +#if defined(__SANITIZE_THREAD__) +#define DWARFS_SANITIZE_THREAD 1 +#elif defined(__has_feature) +#if __has_feature(thread_sanitizer) +#define DWARFS_SANITIZE_THREAD 1 +#endif +#endif diff --git a/include/dwarfs/nilsimsa.h b/include/dwarfs/nilsimsa.h index a8fad849..f8bdd5b8 100644 --- a/include/dwarfs/nilsimsa.h +++ b/include/dwarfs/nilsimsa.h @@ -25,6 +25,8 @@ #include #include +#include "dwarfs/compiler.h" + namespace dwarfs { class nilsimsa { @@ -35,7 +37,14 @@ class nilsimsa { void update(uint8_t const* data, size_t size); std::vector finalize() const; - static int similarity(uint64_t const* a, uint64_t const* b); +#ifndef DWARFS_SANITIZE_THREAD + __attribute__((target("popcnt"))) static int + similarity(uint64_t const* a, uint64_t const* b); + + __attribute__((target("default"))) +#endif + static int + similarity(uint64_t const* a, uint64_t const* b); private: class impl; diff --git a/src/dwarfs/nilsimsa.cpp b/src/dwarfs/nilsimsa.cpp index 31111051..3d802c64 100644 --- a/src/dwarfs/nilsimsa.cpp +++ b/src/dwarfs/nilsimsa.cpp @@ -57,15 +57,6 @@ uint8_t tran3(uint8_t a, uint8_t b, uint8_t c, uint8_t n) { return ((TT53[(a + n) & 0xFF] ^ TT53[b] * (n + n + 1)) + TT53[c ^ TT53[n]]); } -// TODO: this will currently only work for gcc/clang, but should be easy to port -__attribute__((__unused__)) int popcount(unsigned long x) { - return __builtin_popcountl(x); -} - -__attribute__((__unused__)) int popcount(unsigned long long x) { - return __builtin_popcountll(x); -} - } // namespace class nilsimsa::impl { @@ -198,14 +189,39 @@ void nilsimsa::update(uint8_t const* data, size_t size) { std::vector nilsimsa::finalize() const { return impl_->finalize(); } +#ifndef DWARFS_SANITIZE_THREAD +__attribute__((target("popcnt"))) int +nilsimsa::similarity(uint64_t const* a, uint64_t const* b) { + int bits = 0; + + for (int i = 0; i < 4; ++i) { + if constexpr (std::is_same_v) { + bits += __builtin_popcountl(a[i] ^ b[i]); + } else if constexpr (std::is_same_v) { + bits += __builtin_popcountll(a[i] ^ b[i]); + } + } + + return 255 - bits; +} + +__attribute__((target("default"))) +#endif int nilsimsa::similarity(uint64_t const* a, uint64_t const* b) { int bits = 0; for (int i = 0; i < 4; ++i) { - bits += popcount(a[i] ^ b[i]); + if constexpr (std::is_same_v) { + bits += __builtin_popcountl(a[i] ^ b[i]); + } else if constexpr (std::is_same_v) { + bits += __builtin_popcountll(a[i] ^ b[i]); + } } - return 256 - bits; + return 255 - bits; } +static_assert(std::is_same_v || + std::is_same_v); + } // namespace dwarfs