[vm] Popcount via compiler intrinsics.

Change-Id: I8913beea7b984f04cec7f9efc00673aa12095eda
Reviewed-on: https://dart-review.googlesource.com/18423
Reviewed-by: Zach Anderson <zra@google.com>
This commit is contained in:
Ryan Macnak 2017-11-03 16:34:35 +00:00
parent adcb6a7399
commit c4f4cdbf29
4 changed files with 78 additions and 20 deletions

View file

@ -48,6 +48,7 @@
#include <Rpc.h>
#include <VersionHelpers.h>
#include <intrin.h>
#include <shellapi.h>
#include <windows.h>
#include <winsock2.h>

View file

@ -21,17 +21,6 @@ uintptr_t Utils::RoundUpToPowerOfTwo(uintptr_t x) {
return x + 1;
}
// Implementation is from "Hacker's Delight" by Henry S. Warren, Jr.,
// figure 5-2, page 66, where the function is called pop.
int Utils::CountOneBits(uint32_t x) {
x = x - ((x >> 1) & 0x55555555);
x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
x = (x + (x >> 4)) & 0x0F0F0F0F;
x = x + (x >> 8);
x = x + (x >> 16);
return static_cast<int>(x & 0x0000003F);
}
// TODO(koda): Compare to flsll call/intrinsic.
int Utils::HighestBit(int64_t v) {
uint64_t x = static_cast<uint64_t>((v > 0) ? v : -v);

View file

@ -103,7 +103,39 @@ class Utils {
}
static uintptr_t RoundUpToPowerOfTwo(uintptr_t x);
static int CountOneBits(uint32_t x);
static int CountOneBits32(uint32_t x) {
#ifdef _MSC_VER
return __popcnt(x);
#elif __GNUC__
return __builtin_popcount(x);
#else
#error CountOneBits32 not implemented for this compiler
#endif
}
static int CountOneBits64(uint64_t x) {
#ifdef _MSC_VER
#ifdef ARCH_IS_64_BIT
return __popcnt64(x);
#else
return CountOneBits32(static_cast<uint32_t>(x)) +
CountOneBits32(static_cast<uint32_t>(x >> 32));
#endif
#elif __GNUC__
return __builtin_popcountll(x);
#else
#error CountOneBits64 not implemented for this compiler
#endif
}
static int CountOneBitsWord(uword x) {
#ifdef ARCH_IS_64_BIT
return CountOneBits64(x);
#else
return CountOneBits32(x);
#endif
}
static int HighestBit(int64_t v);

View file

@ -98,14 +98,50 @@ VM_UNIT_TEST_CASE(RoundUpToPowerOfTwo) {
EXPECT_EQ(0x10000000U, Utils::RoundUpToPowerOfTwo(0x08765432));
}
VM_UNIT_TEST_CASE(CountOneBits) {
EXPECT_EQ(0, Utils::CountOneBits(0));
EXPECT_EQ(1, Utils::CountOneBits(0x00000010));
EXPECT_EQ(1, Utils::CountOneBits(0x00010000));
EXPECT_EQ(1, Utils::CountOneBits(0x10000000));
EXPECT_EQ(4, Utils::CountOneBits(0x10101010));
EXPECT_EQ(8, Utils::CountOneBits(0x03030303));
EXPECT_EQ(32, Utils::CountOneBits(0xFFFFFFFF));
VM_UNIT_TEST_CASE(CountOneBits32) {
EXPECT_EQ(0, Utils::CountOneBits32(0));
EXPECT_EQ(1, Utils::CountOneBits32(0x00000010));
EXPECT_EQ(1, Utils::CountOneBits32(0x00010000));
EXPECT_EQ(1, Utils::CountOneBits32(0x10000000));
EXPECT_EQ(4, Utils::CountOneBits32(0x10101010));
EXPECT_EQ(8, Utils::CountOneBits32(0x03030303));
EXPECT_EQ(32, Utils::CountOneBits32(0xFFFFFFFF));
}
VM_UNIT_TEST_CASE(CountOneBits64) {
EXPECT_EQ(0, Utils::CountOneBits64(DART_UINT64_C(0)));
EXPECT_EQ(1, Utils::CountOneBits64(DART_UINT64_C(0x00000010)));
EXPECT_EQ(1, Utils::CountOneBits64(DART_UINT64_C(0x00010000)));
EXPECT_EQ(1, Utils::CountOneBits64(DART_UINT64_C(0x10000000)));
EXPECT_EQ(4, Utils::CountOneBits64(DART_UINT64_C(0x10101010)));
EXPECT_EQ(8, Utils::CountOneBits64(DART_UINT64_C(0x03030303)));
EXPECT_EQ(32, Utils::CountOneBits64(DART_UINT64_C(0xFFFFFFFF)));
EXPECT_EQ(2, Utils::CountOneBits64(DART_UINT64_C(0x0000001000000010)));
EXPECT_EQ(2, Utils::CountOneBits64(DART_UINT64_C(0x0001000000010000)));
EXPECT_EQ(2, Utils::CountOneBits64(DART_UINT64_C(0x1000000010000000)));
EXPECT_EQ(8, Utils::CountOneBits64(DART_UINT64_C(0x1010101010101010)));
EXPECT_EQ(16, Utils::CountOneBits64(DART_UINT64_C(0x0303030303030303)));
EXPECT_EQ(64, Utils::CountOneBits64(DART_UINT64_C(0xFFFFFFFFFFFFFFFF)));
}
VM_UNIT_TEST_CASE(CountOneBitsWord) {
EXPECT_EQ(0, Utils::CountOneBitsWord(0));
EXPECT_EQ(1, Utils::CountOneBitsWord(0x00000010));
EXPECT_EQ(1, Utils::CountOneBitsWord(0x00010000));
EXPECT_EQ(1, Utils::CountOneBitsWord(0x10000000));
EXPECT_EQ(4, Utils::CountOneBitsWord(0x10101010));
EXPECT_EQ(8, Utils::CountOneBitsWord(0x03030303));
EXPECT_EQ(32, Utils::CountOneBitsWord(0xFFFFFFFF));
#if defined(ARCH_IS_64_BIT)
EXPECT_EQ(2, Utils::CountOneBitsWord(0x0000001000000010));
EXPECT_EQ(2, Utils::CountOneBitsWord(0x0001000000010000));
EXPECT_EQ(2, Utils::CountOneBitsWord(0x1000000010000000));
EXPECT_EQ(8, Utils::CountOneBitsWord(0x1010101010101010));
EXPECT_EQ(16, Utils::CountOneBitsWord(0x0303030303030303));
EXPECT_EQ(64, Utils::CountOneBitsWord(0xFFFFFFFFFFFFFFFF));
#endif
}
VM_UNIT_TEST_CASE(CountZeros) {