From: Dave Watson Date: Tue, 5 Dec 2017 17:14:34 +0000 (-0800) Subject: bitreverse X-Git-Tag: v2017.12.11.00~27 X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=commitdiff_plain;h=d7629090e2c23da58ffc8977b22ccb17a25ae51c bitreverse Summary: Adds a bitreverse function to Bits.h AFAIK there is no great way to do this on x86, takes ~4-5ns. arm has a single instruction we can drop in in the future. Reviewed By: yfeldblum Differential Revision: D6459283 fbshipit-source-id: 129db196b2fac95386f601ae57843aa87523b915 --- diff --git a/folly/Bits.h b/folly/Bits.h index 529073b2..889b3a0b 100644 --- a/folly/Bits.h +++ b/folly/Bits.h @@ -372,4 +372,13 @@ inline void storeUnaligned(void* p, T value) { } } +template +T bitReverse(T n) { + auto m = static_cast::type>(n); + m = ((m & 0xAAAAAAAAAAAAAAAA) >> 1) | ((m & 0x5555555555555555) << 1); + m = ((m & 0xCCCCCCCCCCCCCCCC) >> 2) | ((m & 0x3333333333333333) << 2); + m = ((m & 0xF0F0F0F0F0F0F0F0) >> 4) | ((m & 0x0F0F0F0F0F0F0F0F) << 4); + return static_cast(Endian::swap(m)); +} + } // namespace folly diff --git a/folly/test/BitsBenchmark.cpp b/folly/test/BitsBenchmark.cpp index 8084a8b6..5d2ba9e1 100644 --- a/folly/test/BitsBenchmark.cpp +++ b/folly/test/BitsBenchmark.cpp @@ -38,6 +38,15 @@ BENCHMARK(isPowTwo, iters) { } } +BENCHMARK_DRAW_LINE(); +BENCHMARK(reverse, iters) { + uint64_t b = 0; + for (unsigned long i = 0; i < iters; ++i) { + b = folly::bitReverse(i + b); + folly::doNotOptimizeAway(b); + } +} + int main(int argc, char** argv) { gflags::ParseCommandLineFlags(&argc, &argv, true); folly::runBenchmarks(); @@ -48,7 +57,13 @@ int main(int argc, char** argv) { Benchmarks run on dual Xeon X5650's @ 2.67GHz w/hyperthreading enabled (12 physical cores, 12 MB cache, 72 GB RAM) -Benchmark Iters Total t t/iter iter/sec ------------------------------------------------------------------------------- -* nextPowTwoClz 1000000 1.659 ms 1.659 ns 574.8 M +============================================================================ +folly/test/BitsBenchmark.cpp relative time/iter iters/s +============================================================================ +nextPowTwoClz 0.00fs Infinity +---------------------------------------------------------------------------- +isPowTwo 731.61ps 1.37G +---------------------------------------------------------------------------- +reverse 4.84ns 206.58M +============================================================================ */ diff --git a/folly/test/BitsTest.cpp b/folly/test/BitsTest.cpp index 810241e1..1d722cb5 100644 --- a/folly/test/BitsTest.cpp +++ b/folly/test/BitsTest.cpp @@ -18,6 +18,7 @@ #include +#include #include #include @@ -185,3 +186,25 @@ TEST(Bits, Endian_swap_real) { EXPECT_NE(d, Endian::swap(d)); EXPECT_EQ(d, Endian::swap(Endian::swap(d))); } + +uint64_t reverse_simple(uint64_t v) { + uint64_t r = 0; + + for (int i = 0; i < 64; i++) { + r <<= 1; + r |= v & 1; + v >>= 1; + } + return r; +} + +TEST(Bits, BitReverse) { + EXPECT_EQ(folly::bitReverse(0), 0); + EXPECT_EQ(folly::bitReverse(1), 128); + for (int i = 0; i < 100; i++) { + uint64_t v = folly::Random::rand64(); + EXPECT_EQ(folly::bitReverse(v), reverse_simple(v)); + uint32_t b = folly::Random::rand32(); + EXPECT_EQ(folly::bitReverse(b), reverse_simple(b) >> 32); + } +}