Skip to content

Commit 6773197

Browse files
committed
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
1 parent 204b0cb commit 6773197

File tree

2 files changed

+70
-11
lines changed

2 files changed

+70
-11
lines changed

src/backend/utils/mmgr/aset.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ AllocSetFreeIndex(Size size)
289289
* or equivalently
290290
* pg_leftmost_one_pos32(size - 1) - ALLOC_MINBITS + 1
291291
*
292-
* However, rather than just calling that function, we duplicate the
292+
* However, for platforms without intrinsic support, we duplicate the
293293
* logic here, allowing an additional optimization. It's reasonable
294294
* to assume that ALLOC_CHUNK_LIMIT fits in 16 bits, so we can unroll
295295
* the byte-at-a-time loop in pg_leftmost_one_pos32 and just handle
@@ -299,8 +299,8 @@ AllocSetFreeIndex(Size size)
299299
* much trouble.
300300
*----------
301301
*/
302-
#ifdef HAVE__BUILTIN_CLZ
303-
idx = 31 - __builtin_clz((uint32) size - 1) - ALLOC_MINBITS + 1;
302+
#ifdef HAVE_BITSCAN_REVERSE
303+
idx = pg_leftmost_one_pos32((uint32) size - 1) - ALLOC_MINBITS + 1;
304304
#else
305305
uint32 t,
306306
tsize;

src/include/port/pg_bitutils.h

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,21 @@
1313
#ifndef PG_BITUTILS_H
1414
#define PG_BITUTILS_H
1515

16+
#ifdef _MSC_VER
17+
#include <intrin.h>
18+
#define HAVE_BITSCAN_FORWARD
19+
#define HAVE_BITSCAN_REVERSE
20+
21+
#else
22+
#if defined(HAVE__BUILTIN_CTZ)
23+
#define HAVE_BITSCAN_FORWARD
24+
#endif
25+
26+
#if defined(HAVE__BUILTIN_CLZ)
27+
#define HAVE_BITSCAN_REVERSE
28+
#endif
29+
#endif /* _MSC_VER */
30+
1631
extern PGDLLIMPORT const uint8 pg_leftmost_one_pos[256];
1732
extern PGDLLIMPORT const uint8 pg_rightmost_one_pos[256];
1833
extern PGDLLIMPORT const uint8 pg_number_of_ones[256];
@@ -27,9 +42,12 @@ pg_leftmost_one_pos32(uint32 word)
2742
{
2843
#ifdef HAVE__BUILTIN_CLZ
2944
int bitscan_result;
45+
#elif defined(_MSC_VER)
46+
unsigned long bitscan_result;
47+
bool non_zero;
3048
#endif
3149

32-
#if !defined(HAVE__BUILTIN_CLZ) || defined(USE_ASSERT_CHECKING)
50+
#if !defined(HAVE_BITSCAN_REVERSE) || defined(USE_ASSERT_CHECKING)
3351
int result;
3452
int shift = 32 - 8;
3553

@@ -41,13 +59,20 @@ pg_leftmost_one_pos32(uint32 word)
4159
result = shift + pg_leftmost_one_pos[(word >> shift) & 255];
4260
#endif
4361

62+
#ifdef HAVE_BITSCAN_REVERSE
63+
4464
#if defined(HAVE__BUILTIN_CLZ)
4565
bitscan_result = 31 - __builtin_clz(word);
66+
#elif defined(_MSC_VER)
67+
non_zero = _BitScanReverse(&bitscan_result, word);
68+
Assert(non_zero);
69+
#endif
4670
Assert(bitscan_result == result);
4771
return bitscan_result;
72+
4873
#else
4974
return result;
50-
#endif /* HAVE__BUILTIN_CLZ */
75+
#endif /* HAVE_BITSCAN_REVERSE */
5176
}
5277

5378
/*
@@ -59,9 +84,12 @@ pg_leftmost_one_pos64(uint64 word)
5984
{
6085
#ifdef HAVE__BUILTIN_CLZ
6186
int bitscan_result;
87+
#elif defined(_MSC_VER)
88+
unsigned long bitscan_result;
89+
bool non_zero;
6290
#endif
6391

64-
#if !defined(HAVE__BUILTIN_CLZ) || defined(USE_ASSERT_CHECKING)
92+
#if !defined(HAVE_BITSCAN_REVERSE) || defined(USE_ASSERT_CHECKING)
6593
int result;
6694
int shift = 64 - 8;
6795

@@ -73,6 +101,8 @@ pg_leftmost_one_pos64(uint64 word)
73101
result = shift + pg_leftmost_one_pos[(word >> shift) & 255];
74102
#endif
75103

104+
#ifdef HAVE_BITSCAN_REVERSE
105+
76106
#if defined(HAVE__BUILTIN_CLZ)
77107
#if defined(HAVE_LONG_INT_64)
78108
bitscan_result = 63 - __builtin_clzl(word);
@@ -81,11 +111,17 @@ pg_leftmost_one_pos64(uint64 word)
81111
#else
82112
#error must have a working 64-bit integer datatype
83113
#endif /* HAVE_LONG_INT_64 */
114+
115+
#elif defined(_MSC_VER)
116+
non_zero = _BitScanReverse64(&bitscan_result, word);
117+
Assert(non_zero);
118+
#endif /* HAVE__BUILTIN_CLZ */
84119
Assert(bitscan_result == result);
85120
return bitscan_result;
121+
86122
#else
87123
return result;
88-
#endif /* HAVE__BUILTIN_CLZ */
124+
#endif /* HAVE_BITSCAN_REVERSE */
89125
}
90126

91127
/*
@@ -99,9 +135,13 @@ pg_rightmost_one_pos32(uint32 word)
99135
#ifdef HAVE__BUILTIN_CTZ
100136
const uint32 orig_word = word;
101137
int bitscan_result;
138+
#elif defined(_MSC_VER)
139+
const unsigned long orig_word = word;
140+
unsigned long bitscan_result;
141+
bool non_zero;
102142
#endif
103143

104-
#if !defined(HAVE__BUILTIN_CTZ) || defined(USE_ASSERT_CHECKING)
144+
#if !defined(HAVE_BITSCAN_FORWARD) || defined(USE_ASSERT_CHECKING)
105145
int result = 0;
106146

107147
Assert(word != 0);
@@ -114,13 +154,20 @@ pg_rightmost_one_pos32(uint32 word)
114154
result += pg_rightmost_one_pos[word & 255];
115155
#endif
116156

157+
#ifdef HAVE_BITSCAN_FORWARD
158+
117159
#if defined(HAVE__BUILTIN_CTZ)
118160
bitscan_result = __builtin_ctz(orig_word);
161+
#elif defined(_MSC_VER)
162+
non_zero = _BitScanForward(&bitscan_result, orig_word);
163+
Assert(non_zero);
164+
#endif
119165
Assert(bitscan_result == result);
120166
return bitscan_result;
167+
121168
#else
122169
return result;
123-
#endif /* HAVE__BUILTIN_CTZ */
170+
#endif /* HAVE_BITSCAN_FORWARD */
124171
}
125172

126173
/*
@@ -133,9 +180,13 @@ pg_rightmost_one_pos64(uint64 word)
133180
#ifdef HAVE__BUILTIN_CTZ
134181
const uint64 orig_word = word;
135182
int bitscan_result;
183+
#elif defined(_MSC_VER)
184+
const unsigned __int64 orig_word = word;
185+
unsigned long bitscan_result;
186+
bool non_zero;
136187
#endif
137188

138-
#if !defined(HAVE__BUILTIN_CTZ) || defined(USE_ASSERT_CHECKING)
189+
#if !defined(HAVE_BITSCAN_FORWARD) || defined(USE_ASSERT_CHECKING)
139190
int result = 0;
140191

141192
Assert(word != 0);
@@ -148,6 +199,8 @@ pg_rightmost_one_pos64(uint64 word)
148199
result += pg_rightmost_one_pos[word & 255];
149200
#endif
150201

202+
#ifdef HAVE_BITSCAN_FORWARD
203+
151204
#if defined(HAVE__BUILTIN_CTZ)
152205
#if defined(HAVE_LONG_INT_64)
153206
bitscan_result = __builtin_ctzl(orig_word);
@@ -156,11 +209,17 @@ pg_rightmost_one_pos64(uint64 word)
156209
#else
157210
#error must have a working 64-bit integer datatype
158211
#endif /* HAVE_LONG_INT_64 */
212+
213+
#elif defined(_MSC_VER)
214+
non_zero = _BitScanForward64(&bitscan_result, orig_word);
215+
Assert(non_zero);
216+
#endif /* HAVE__BUILTIN_CTZ */
159217
Assert(bitscan_result == result);
160218
return bitscan_result;
219+
161220
#else
162221
return result;
163-
#endif /* HAVE__BUILTIN_CTZ */
222+
#endif /* HAVE_BITSCAN_FORWARD */
164223
}
165224

166225
/*

0 commit comments

Comments
 (0)