aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDavid Rowley <drowley@postgresql.org>2021-08-09 15:23:48 +1200
committerDavid Rowley <drowley@postgresql.org>2021-08-09 15:23:48 +1200
commit2e281249af6c702fd057f34150fd9ac6cb8c7a8b (patch)
tree23ef522b70de28dabdb7c590f175998a1627c234 /src
parentd8a75b1308b133502ae3f02be485e9cd4eda9803 (diff)
downloadpostgresql-2e281249af6c702fd057f34150fd9ac6cb8c7a8b.tar.gz
postgresql-2e281249af6c702fd057f34150fd9ac6cb8c7a8b.zip
Add POPCNT support for MSVC x86_64 builds
02a6a54ec added code to make use of the POPCNT instruction when available for many of our common platforms. Here we do the same for MSVC for x86_64 machines. MSVC's intrinsic functions for popcnt seem to differ from GCCs in that they always appear to emit the popcnt instructions. In GCC the behavior will depend on if the source file was compiled with -mpopcnt or not. For this reason, the MSVC intrinsic function has been lumped into the pg_popcount*_asm function, however doing that sort of invalidates the name of that function, so let's rename it to pg_popcount*_fast(). Author: David Rowley Reviewed-by: John Naylor Discussion: https://postgr.es/m/CAApHDvqL3cbbK%3DGzNcwzsNR9Gi%2BaUvTudKkC4XgnQfXirJ_oRQ%40mail.gmail.com
Diffstat (limited to 'src')
-rw-r--r--src/port/pg_bitutils.c48
1 files changed, 33 insertions, 15 deletions
diff --git a/src/port/pg_bitutils.c b/src/port/pg_bitutils.c
index 2252021854f..10676b285ca 100644
--- a/src/port/pg_bitutils.c
+++ b/src/port/pg_bitutils.c
@@ -104,6 +104,16 @@ const uint8 pg_number_of_ones[256] = {
};
/*
+ * With MSVC on x86_64 builds, try using native popcnt instructions via the
+ * __popcnt and __popcnt64 intrinsics. These don't work the same as GCC's
+ * __builtin_popcount* intrinsic functions as they always emit popcnt
+ * instructions.
+ */
+#if defined(_MSC_VER) && defined(_M_AMD64)
+#define HAVE_X86_64_POPCNTQ
+#endif
+
+/*
* On x86_64, we can use the hardware popcount instruction, but only if
* we can verify that the CPU supports it via the cpuid instruction.
*
@@ -112,28 +122,28 @@ const uint8 pg_number_of_ones[256] = {
*/
#ifdef HAVE_X86_64_POPCNTQ
#if defined(HAVE__GET_CPUID) || defined(HAVE__CPUID)
-#define USE_POPCNT_ASM 1
+#define TRY_POPCNT_FAST 1
#endif
#endif
static int pg_popcount32_slow(uint32 word);
static int pg_popcount64_slow(uint64 word);
-#ifdef USE_POPCNT_ASM
+#ifdef TRY_POPCNT_FAST
static bool pg_popcount_available(void);
static int pg_popcount32_choose(uint32 word);
static int pg_popcount64_choose(uint64 word);
-static int pg_popcount32_asm(uint32 word);
-static int pg_popcount64_asm(uint64 word);
+static int pg_popcount32_fast(uint32 word);
+static int pg_popcount64_fast(uint64 word);
int (*pg_popcount32) (uint32 word) = pg_popcount32_choose;
int (*pg_popcount64) (uint64 word) = pg_popcount64_choose;
#else
int (*pg_popcount32) (uint32 word) = pg_popcount32_slow;
int (*pg_popcount64) (uint64 word) = pg_popcount64_slow;
-#endif /* USE_POPCNT_ASM */
+#endif /* TRY_POPCNT_FAST */
-#ifdef USE_POPCNT_ASM
+#ifdef TRY_POPCNT_FAST
/*
* Return true if CPUID indicates that the POPCNT instruction is available.
@@ -165,8 +175,8 @@ pg_popcount32_choose(uint32 word)
{
if (pg_popcount_available())
{
- pg_popcount32 = pg_popcount32_asm;
- pg_popcount64 = pg_popcount64_asm;
+ pg_popcount32 = pg_popcount32_fast;
+ pg_popcount64 = pg_popcount64_fast;
}
else
{
@@ -182,8 +192,8 @@ pg_popcount64_choose(uint64 word)
{
if (pg_popcount_available())
{
- pg_popcount32 = pg_popcount32_asm;
- pg_popcount64 = pg_popcount64_asm;
+ pg_popcount32 = pg_popcount32_fast;
+ pg_popcount64 = pg_popcount64_fast;
}
else
{
@@ -195,32 +205,40 @@ pg_popcount64_choose(uint64 word)
}
/*
- * pg_popcount32_asm
+ * pg_popcount32_fast
* Return the number of 1 bits set in word
*/
static int
-pg_popcount32_asm(uint32 word)
+pg_popcount32_fast(uint32 word)
{
+#ifdef _MSC_VER
+ return __popcnt(word);
+#else
uint32 res;
__asm__ __volatile__(" popcntl %1,%0\n":"=q"(res):"rm"(word):"cc");
return (int) res;
+#endif
}
/*
- * pg_popcount64_asm
+ * pg_popcount64_fast
* Return the number of 1 bits set in word
*/
static int
-pg_popcount64_asm(uint64 word)
+pg_popcount64_fast(uint64 word)
{
+#ifdef _MSC_VER
+ return __popcnt64(word);
+#else
uint64 res;
__asm__ __volatile__(" popcntq %1,%0\n":"=q"(res):"rm"(word):"cc");
return (int) res;
+#endif
}
-#endif /* USE_POPCNT_ASM */
+#endif /* TRY_POPCNT_FAST */
/*