summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Naylor2023-02-08 05:05:58 +0000
committerJohn Naylor2023-02-20 07:55:32 +0000
commit67731974644ce77129d282434065c3f0be04be92 (patch)
tree7bb36feeb6086a8985dc9fe3386c8146ff71911d
parent204b0cbecb82ab3fde2e12998a89e7227cd64094 (diff)
Add MSVC support for pg_leftmost_one_pos32() and friends
To allow testing for general support for fast bitscan intrinsics, add symbols HAVE_BITSCAN_REVERSE and HAVE_BITSCAN_FORWARD. Also do related cleanup in AllocSetFreeIndex(): Previously, we tested for HAVE__BUILTIN_CLZ and copied the relevant internals of pg_leftmost_one_pos32(), with a special fallback that does less work than the general fallback for that function. Now that we have a more general test, we just call pg_leftmost_one_pos32() directly for platforms with intrinsic support. On gcc at least, there is no difference in the binary for non-assert builds. Discussion: https://www.postgresql.org/message-id/CAFBsxsEPc%2BFnX_0vmmQ5DHv60sk4rL_RZJ%2BMD6ei%3D76L0kFMvA%40mail.gmail.com
-rw-r--r--src/backend/utils/mmgr/aset.c6
-rw-r--r--src/include/port/pg_bitutils.h75
2 files changed, 70 insertions, 11 deletions
diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c
index 740729b5d0..026f545676 100644
--- a/src/backend/utils/mmgr/aset.c
+++ b/src/backend/utils/mmgr/aset.c
@@ -289,7 +289,7 @@ AllocSetFreeIndex(Size size)
* or equivalently
* pg_leftmost_one_pos32(size - 1) - ALLOC_MINBITS + 1
*
- * However, rather than just calling that function, we duplicate the
+ * However, for platforms without intrinsic support, we duplicate the
* logic here, allowing an additional optimization. It's reasonable
* to assume that ALLOC_CHUNK_LIMIT fits in 16 bits, so we can unroll
* the byte-at-a-time loop in pg_leftmost_one_pos32 and just handle
@@ -299,8 +299,8 @@ AllocSetFreeIndex(Size size)
* much trouble.
*----------
*/
-#ifdef HAVE__BUILTIN_CLZ
- idx = 31 - __builtin_clz((uint32) size - 1) - ALLOC_MINBITS + 1;
+#ifdef HAVE_BITSCAN_REVERSE
+ idx = pg_leftmost_one_pos32((uint32) size - 1) - ALLOC_MINBITS + 1;
#else
uint32 t,
tsize;
diff --git a/src/include/port/pg_bitutils.h b/src/include/port/pg_bitutils.h
index a5df4f1a35..9150789aaf 100644
--- a/src/include/port/pg_bitutils.h
+++ b/src/include/port/pg_bitutils.h
@@ -13,6 +13,21 @@
#ifndef PG_BITUTILS_H
#define PG_BITUTILS_H
+#ifdef _MSC_VER
+#include <intrin.h>
+#define HAVE_BITSCAN_FORWARD
+#define HAVE_BITSCAN_REVERSE
+
+#else
+#if defined(HAVE__BUILTIN_CTZ)
+#define HAVE_BITSCAN_FORWARD
+#endif
+
+#if defined(HAVE__BUILTIN_CLZ)
+#define HAVE_BITSCAN_REVERSE
+#endif
+#endif /* _MSC_VER */
+
extern PGDLLIMPORT const uint8 pg_leftmost_one_pos[256];
extern PGDLLIMPORT const uint8 pg_rightmost_one_pos[256];
extern PGDLLIMPORT const uint8 pg_number_of_ones[256];
@@ -27,9 +42,12 @@ pg_leftmost_one_pos32(uint32 word)
{
#ifdef HAVE__BUILTIN_CLZ
int bitscan_result;
+#elif defined(_MSC_VER)
+ unsigned long bitscan_result;
+ bool non_zero;
#endif
-#if !defined(HAVE__BUILTIN_CLZ) || defined(USE_ASSERT_CHECKING)
+#if !defined(HAVE_BITSCAN_REVERSE) || defined(USE_ASSERT_CHECKING)
int result;
int shift = 32 - 8;
@@ -41,13 +59,20 @@ pg_leftmost_one_pos32(uint32 word)
result = shift + pg_leftmost_one_pos[(word >> shift) & 255];
#endif
+#ifdef HAVE_BITSCAN_REVERSE
+
#if defined(HAVE__BUILTIN_CLZ)
bitscan_result = 31 - __builtin_clz(word);
+#elif defined(_MSC_VER)
+ non_zero = _BitScanReverse(&bitscan_result, word);
+ Assert(non_zero);
+#endif
Assert(bitscan_result == result);
return bitscan_result;
+
#else
return result;
-#endif /* HAVE__BUILTIN_CLZ */
+#endif /* HAVE_BITSCAN_REVERSE */
}
/*
@@ -59,9 +84,12 @@ pg_leftmost_one_pos64(uint64 word)
{
#ifdef HAVE__BUILTIN_CLZ
int bitscan_result;
+#elif defined(_MSC_VER)
+ unsigned long bitscan_result;
+ bool non_zero;
#endif
-#if !defined(HAVE__BUILTIN_CLZ) || defined(USE_ASSERT_CHECKING)
+#if !defined(HAVE_BITSCAN_REVERSE) || defined(USE_ASSERT_CHECKING)
int result;
int shift = 64 - 8;
@@ -73,6 +101,8 @@ pg_leftmost_one_pos64(uint64 word)
result = shift + pg_leftmost_one_pos[(word >> shift) & 255];
#endif
+#ifdef HAVE_BITSCAN_REVERSE
+
#if defined(HAVE__BUILTIN_CLZ)
#if defined(HAVE_LONG_INT_64)
bitscan_result = 63 - __builtin_clzl(word);
@@ -81,11 +111,17 @@ pg_leftmost_one_pos64(uint64 word)
#else
#error must have a working 64-bit integer datatype
#endif /* HAVE_LONG_INT_64 */
+
+#elif defined(_MSC_VER)
+ non_zero = _BitScanReverse64(&bitscan_result, word);
+ Assert(non_zero);
+#endif /* HAVE__BUILTIN_CLZ */
Assert(bitscan_result == result);
return bitscan_result;
+
#else
return result;
-#endif /* HAVE__BUILTIN_CLZ */
+#endif /* HAVE_BITSCAN_REVERSE */
}
/*
@@ -99,9 +135,13 @@ pg_rightmost_one_pos32(uint32 word)
#ifdef HAVE__BUILTIN_CTZ
const uint32 orig_word = word;
int bitscan_result;
+#elif defined(_MSC_VER)
+ const unsigned long orig_word = word;
+ unsigned long bitscan_result;
+ bool non_zero;
#endif
-#if !defined(HAVE__BUILTIN_CTZ) || defined(USE_ASSERT_CHECKING)
+#if !defined(HAVE_BITSCAN_FORWARD) || defined(USE_ASSERT_CHECKING)
int result = 0;
Assert(word != 0);
@@ -114,13 +154,20 @@ pg_rightmost_one_pos32(uint32 word)
result += pg_rightmost_one_pos[word & 255];
#endif
+#ifdef HAVE_BITSCAN_FORWARD
+
#if defined(HAVE__BUILTIN_CTZ)
bitscan_result = __builtin_ctz(orig_word);
+#elif defined(_MSC_VER)
+ non_zero = _BitScanForward(&bitscan_result, orig_word);
+ Assert(non_zero);
+#endif
Assert(bitscan_result == result);
return bitscan_result;
+
#else
return result;
-#endif /* HAVE__BUILTIN_CTZ */
+#endif /* HAVE_BITSCAN_FORWARD */
}
/*
@@ -133,9 +180,13 @@ pg_rightmost_one_pos64(uint64 word)
#ifdef HAVE__BUILTIN_CTZ
const uint64 orig_word = word;
int bitscan_result;
+#elif defined(_MSC_VER)
+ const unsigned __int64 orig_word = word;
+ unsigned long bitscan_result;
+ bool non_zero;
#endif
-#if !defined(HAVE__BUILTIN_CTZ) || defined(USE_ASSERT_CHECKING)
+#if !defined(HAVE_BITSCAN_FORWARD) || defined(USE_ASSERT_CHECKING)
int result = 0;
Assert(word != 0);
@@ -148,6 +199,8 @@ pg_rightmost_one_pos64(uint64 word)
result += pg_rightmost_one_pos[word & 255];
#endif
+#ifdef HAVE_BITSCAN_FORWARD
+
#if defined(HAVE__BUILTIN_CTZ)
#if defined(HAVE_LONG_INT_64)
bitscan_result = __builtin_ctzl(orig_word);
@@ -156,11 +209,17 @@ pg_rightmost_one_pos64(uint64 word)
#else
#error must have a working 64-bit integer datatype
#endif /* HAVE_LONG_INT_64 */
+
+#elif defined(_MSC_VER)
+ non_zero = _BitScanForward64(&bitscan_result, orig_word);
+ Assert(non_zero);
+#endif /* HAVE__BUILTIN_CTZ */
Assert(bitscan_result == result);
return bitscan_result;
+
#else
return result;
-#endif /* HAVE__BUILTIN_CTZ */
+#endif /* HAVE_BITSCAN_FORWARD */
}
/*