mirror of https://github.com/postgres/postgres
This reverts commitspull/38/headfc6c72747a
,109de05cbb
,d0b4663c23
and711bab1e4d
. Somebody will have to try harder before submitting this patch again. I've spent entirely too much time on it already, and the #ifdef maze yet to be written in order for it to build at all got on my nerves. The amount of work needed to get a platform-specific performance improvement that's barely above the noise level is not worth it.
parent
e89f14e2bb
commit
457aef0f1f
@ -1,186 +0,0 @@ |
|||||||
/*------------------------------------------------------------------------ -
|
|
||||||
* |
|
||||||
* pg_bitutils.h |
|
||||||
* miscellaneous functions for bit-wise operations. |
|
||||||
* |
|
||||||
* |
|
||||||
* Portions Copyright(c) 2019, PostgreSQL Global Development Group |
|
||||||
* |
|
||||||
* src/include/port/pg_bitutils.h |
|
||||||
* |
|
||||||
*------------------------------------------------------------------------ - |
|
||||||
*/ |
|
||||||
#ifndef PG_BITUTILS_H |
|
||||||
#define PG_BITUTILS_H |
|
||||||
|
|
||||||
extern int (*pg_popcount32) (uint32 word); |
|
||||||
extern int (*pg_popcount64) (uint64 word); |
|
||||||
extern uint64 pg_popcount(const char *buf, int bytes); |
|
||||||
|
|
||||||
/* in pg_bitutils_hwpopcnt.c */ |
|
||||||
extern int pg_popcount32_hw(uint32 word); |
|
||||||
extern int pg_popcount64_hw(uint64 word); |
|
||||||
|
|
||||||
|
|
||||||
#ifndef HAVE__BUILTIN_CTZ |
|
||||||
/*
|
|
||||||
* Array marking the position of the right-most set bit for each value of |
|
||||||
* 1-255. We count the right-most position as the 0th bit, and the |
|
||||||
* left-most the 7th bit. The 0th index of the array must not be used. |
|
||||||
*/ |
|
||||||
static const uint8 rightmost_one_pos[256] = { |
|
||||||
0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
|
||||||
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
|
||||||
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
|
||||||
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
|
||||||
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
|
||||||
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
|
||||||
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
|
||||||
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
|
||||||
7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
|
||||||
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
|
||||||
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
|
||||||
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
|
||||||
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
|
||||||
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
|
||||||
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, |
|
||||||
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 |
|
||||||
}; |
|
||||||
#endif /* !HAVE__BUILTIN_CTZ */ |
|
||||||
|
|
||||||
/*
|
|
||||||
* pg_rightmost_one32 |
|
||||||
* Returns the number of trailing 0-bits in word, starting at the least |
|
||||||
* significant bit position. word must not be 0. |
|
||||||
*/ |
|
||||||
static inline int |
|
||||||
pg_rightmost_one32(uint32 word) |
|
||||||
{ |
|
||||||
int result = 0; |
|
||||||
|
|
||||||
Assert(word != 0); |
|
||||||
|
|
||||||
#ifdef HAVE__BUILTIN_CTZ |
|
||||||
result = __builtin_ctz(word); |
|
||||||
#else |
|
||||||
while ((word & 255) == 0) |
|
||||||
{ |
|
||||||
word >>= 8; |
|
||||||
result += 8; |
|
||||||
} |
|
||||||
result += rightmost_one_pos[word & 255]; |
|
||||||
#endif /* HAVE__BUILTIN_CTZ */ |
|
||||||
|
|
||||||
return result; |
|
||||||
} |
|
||||||
|
|
||||||
/*
|
|
||||||
* pg_rightmost_one64 |
|
||||||
* Returns the number of trailing 0-bits in word, starting at the least |
|
||||||
* significant bit position. word must not be 0. |
|
||||||
*/ |
|
||||||
static inline int |
|
||||||
pg_rightmost_one64(uint64 word) |
|
||||||
{ |
|
||||||
int result = 0; |
|
||||||
|
|
||||||
Assert(word != 0); |
|
||||||
#ifdef HAVE__BUILTIN_CTZ |
|
||||||
#if defined(HAVE_LONG_INT_64) |
|
||||||
return __builtin_ctzl(word); |
|
||||||
#elif defined(HAVE_LONG_LONG_INT_64) |
|
||||||
return __builtin_ctzll(word); |
|
||||||
#else |
|
||||||
#error must have a working 64-bit integer datatype |
|
||||||
#endif |
|
||||||
#else /* HAVE__BUILTIN_CTZ */ |
|
||||||
while ((word & 255) == 0) |
|
||||||
{ |
|
||||||
word >>= 8; |
|
||||||
result += 8; |
|
||||||
} |
|
||||||
result += rightmost_one_pos[word & 255]; |
|
||||||
#endif |
|
||||||
|
|
||||||
return result; |
|
||||||
} |
|
||||||
|
|
||||||
#ifndef HAVE__BUILTIN_CLZ |
|
||||||
/*
|
|
||||||
* Array marking the position of the left-most set bit for each value of |
|
||||||
* 1-255. We count the right-most position as the 0th bit, and the |
|
||||||
* left-most the 7th bit. The 0th index of the array must not be used. |
|
||||||
*/ |
|
||||||
static const uint8 leftmost_one_pos[256] = { |
|
||||||
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, |
|
||||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, |
|
||||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, |
|
||||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, |
|
||||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, |
|
||||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, |
|
||||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, |
|
||||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, |
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
|
||||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 |
|
||||||
}; |
|
||||||
#endif /* !HAVE_BUILTIN_CLZ */ |
|
||||||
|
|
||||||
/*
|
|
||||||
* pg_leftmost_one32 |
|
||||||
* Returns the 0-based position of the most significant set bit in word |
|
||||||
* measured from the least significant bit. word must not be 0. |
|
||||||
*/ |
|
||||||
static inline int |
|
||||||
pg_leftmost_one32(uint32 word) |
|
||||||
{ |
|
||||||
#ifdef HAVE__BUILTIN_CLZ |
|
||||||
Assert(word != 0); |
|
||||||
|
|
||||||
return 31 - __builtin_clz(word); |
|
||||||
#else |
|
||||||
int shift = 32 - 8; |
|
||||||
|
|
||||||
Assert(word != 0); |
|
||||||
|
|
||||||
while ((word >> shift) == 0) |
|
||||||
shift -= 8; |
|
||||||
|
|
||||||
return shift + leftmost_one_pos[(word >> shift) & 255]; |
|
||||||
#endif /* HAVE__BUILTIN_CLZ */ |
|
||||||
} |
|
||||||
|
|
||||||
/*
|
|
||||||
* pg_leftmost_one64 |
|
||||||
* Returns the 0-based position of the most significant set bit in word |
|
||||||
* measured from the least significant bit. word must not be 0. |
|
||||||
*/ |
|
||||||
static inline int |
|
||||||
pg_leftmost_one64(uint64 word) |
|
||||||
{ |
|
||||||
#ifdef HAVE__BUILTIN_CLZ |
|
||||||
Assert(word != 0); |
|
||||||
#if defined(HAVE_LONG_INT_64) |
|
||||||
return 63 - __builtin_clzl(word); |
|
||||||
#elif defined(HAVE_LONG_LONG_INT_64) |
|
||||||
return 63 - __builtin_clzll(word); |
|
||||||
#else |
|
||||||
#error must have a working 64-bit integer datatype |
|
||||||
#endif |
|
||||||
#else /* HAVE__BUILTIN_CLZ */ |
|
||||||
int shift = 64 - 8; |
|
||||||
|
|
||||||
Assert(word != 0); |
|
||||||
while ((word >> shift) == 0) |
|
||||||
shift -= 8; |
|
||||||
|
|
||||||
return shift + leftmost_one_pos[(word >> shift) & 255]; |
|
||||||
#endif /* !HAVE__BUIILTIN_CLZ */ |
|
||||||
} |
|
||||||
|
|
||||||
#endif /* PG_BITUTILS_H */ |
|
@ -1,219 +0,0 @@ |
|||||||
/*-------------------------------------------------------------------------
|
|
||||||
* |
|
||||||
* pg_bitutils.c |
|
||||||
* miscellaneous functions for bit-wise operations. |
|
||||||
* |
|
||||||
* Portions Copyright (c) 2019, PostgreSQL Global Development Group |
|
||||||
* |
|
||||||
* IDENTIFICATION |
|
||||||
* src/port/pg_bitutils.c |
|
||||||
* |
|
||||||
*------------------------------------------------------------------------- |
|
||||||
*/ |
|
||||||
#include "postgres.h" |
|
||||||
|
|
||||||
#ifdef HAVE__GET_CPUID |
|
||||||
#include <cpuid.h> |
|
||||||
#endif |
|
||||||
|
|
||||||
#ifdef HAVE__CPUID |
|
||||||
#include <intrin.h> |
|
||||||
#endif |
|
||||||
|
|
||||||
#include "port/pg_bitutils.h" |
|
||||||
|
|
||||||
#ifdef HAVE__BUILTIN_POPCOUNT |
|
||||||
static bool pg_popcount_available(void); |
|
||||||
static int pg_popcount32_choose(uint32 word); |
|
||||||
static int pg_popcount32_builtin(uint32 word); |
|
||||||
static int pg_popcount64_choose(uint64 word); |
|
||||||
static int pg_popcount64_builtin(uint64 word); |
|
||||||
int (*pg_popcount32) (uint32 word) = pg_popcount32_choose; |
|
||||||
int (*pg_popcount64) (uint64 word) = pg_popcount64_choose; |
|
||||||
#else |
|
||||||
static int pg_popcount32_slow(uint32 word); |
|
||||||
static int pg_popcount64_slow(uint64 word); |
|
||||||
int (*pg_popcount32) (uint32 word) = pg_popcount32_slow; |
|
||||||
int (*pg_popcount64) (uint64 word) = pg_popcount64_slow; |
|
||||||
#endif /* !HAVE_BUILTIN_POPCOUNT */ |
|
||||||
|
|
||||||
|
|
||||||
/* Array marking the number of 1-bits for each value of 0-255. */ |
|
||||||
static const uint8 number_of_ones[256] = { |
|
||||||
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, |
|
||||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, |
|
||||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, |
|
||||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
|
||||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, |
|
||||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
|
||||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
|
||||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, |
|
||||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, |
|
||||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
|
||||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
|
||||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, |
|
||||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, |
|
||||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, |
|
||||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, |
|
||||||
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 |
|
||||||
}; |
|
||||||
|
|
||||||
/*
|
|
||||||
* Return true iff we have CPUID support and it indicates that the POPCNT |
|
||||||
* instruction is available. |
|
||||||
*/ |
|
||||||
static bool |
|
||||||
pg_popcount_available(void) |
|
||||||
{ |
|
||||||
#if defined(HAVE__GET_CPUID) || defined(HAVE__CPUID) |
|
||||||
unsigned int exx[4] = {0, 0, 0, 0}; |
|
||||||
|
|
||||||
#if defined(HAVE__GET_CPUID) |
|
||||||
__get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]); |
|
||||||
#elif defined(HAVE__CPUID) |
|
||||||
__cpuid(exx, 1); |
|
||||||
#endif |
|
||||||
|
|
||||||
return (exx[2] & (1 << 23)) != 0; /* POPCNT */ |
|
||||||
#else /* HAVE__GET_CPUID || HAVE__CPUID */ |
|
||||||
|
|
||||||
return false; |
|
||||||
#endif |
|
||||||
} |
|
||||||
|
|
||||||
#ifdef HAVE__BUILTIN_POPCOUNT |
|
||||||
/*
|
|
||||||
* This gets called on the first call to pg_popcount32. It replaces the |
|
||||||
* function pointer so that subsequent calls are routed directly to the chosen |
|
||||||
* implementation. |
|
||||||
*/ |
|
||||||
static int |
|
||||||
pg_popcount32_choose(uint32 word) |
|
||||||
{ |
|
||||||
if (pg_popcount_available()) |
|
||||||
pg_popcount32 = pg_popcount32_hw; |
|
||||||
else |
|
||||||
pg_popcount32 = pg_popcount32_builtin; |
|
||||||
|
|
||||||
return pg_popcount32(word); |
|
||||||
} |
|
||||||
|
|
||||||
static int |
|
||||||
pg_popcount32_builtin(uint32 word) |
|
||||||
{ |
|
||||||
return __builtin_popcount(word); |
|
||||||
} |
|
||||||
#else /* HAVE__BUILTIN_POPCOUNT */ |
|
||||||
/*
|
|
||||||
* pg_popcount32_slow |
|
||||||
* Return the number of 1 bits set in word |
|
||||||
*/ |
|
||||||
static int |
|
||||||
pg_popcount32_slow(uint32 word) |
|
||||||
{ |
|
||||||
int result = 0; |
|
||||||
|
|
||||||
while (word != 0) |
|
||||||
{ |
|
||||||
result += number_of_ones[word & 255]; |
|
||||||
word >>= 8; |
|
||||||
} |
|
||||||
|
|
||||||
return result; |
|
||||||
} |
|
||||||
#endif |
|
||||||
|
|
||||||
/*
|
|
||||||
* pg_popcount |
|
||||||
* Returns the number of 1-bits in buf |
|
||||||
*/ |
|
||||||
uint64 |
|
||||||
pg_popcount(const char *buf, int bytes) |
|
||||||
{ |
|
||||||
uint64 popcnt = 0; |
|
||||||
|
|
||||||
#if SIZEOF_VOID_P >= 8 |
|
||||||
/* Process in 64-bit chunks if the buffer is aligned. */ |
|
||||||
if (buf == (char *) TYPEALIGN(8, buf)) |
|
||||||
{ |
|
||||||
uint64 *words = (uint64 *) buf; |
|
||||||
|
|
||||||
while (bytes >= 8) |
|
||||||
{ |
|
||||||
popcnt += pg_popcount64(*words++); |
|
||||||
bytes -= 8; |
|
||||||
} |
|
||||||
|
|
||||||
buf = (char *) words; |
|
||||||
} |
|
||||||
#else |
|
||||||
/* Process in 32-bit chunks if the buffer is aligned. */ |
|
||||||
if (buf == (char *) TYPEALIGN(4, buf)) |
|
||||||
{ |
|
||||||
uint32 *words = (uint32 *) buf; |
|
||||||
|
|
||||||
while (bytes >= 4) |
|
||||||
{ |
|
||||||
popcnt += pg_popcount32(*words++); |
|
||||||
bytes -= 4; |
|
||||||
} |
|
||||||
|
|
||||||
buf = (char *) words; |
|
||||||
} |
|
||||||
#endif |
|
||||||
|
|
||||||
/* Process any remaining bytes */ |
|
||||||
while (bytes--) |
|
||||||
popcnt += number_of_ones[(unsigned char) *buf++]; |
|
||||||
|
|
||||||
return popcnt; |
|
||||||
} |
|
||||||
|
|
||||||
#ifdef HAVE__BUILTIN_POPCOUNT |
|
||||||
/*
|
|
||||||
* This gets called on the first call to pg_popcount64. It replaces the |
|
||||||
* function pointer so that subsequent calls are routed directly to the chosen |
|
||||||
* implementation. |
|
||||||
*/ |
|
||||||
static int |
|
||||||
pg_popcount64_choose(uint64 word) |
|
||||||
{ |
|
||||||
if (pg_popcount_available()) |
|
||||||
pg_popcount64 = pg_popcount64_hw; |
|
||||||
else |
|
||||||
pg_popcount64 = pg_popcount64_builtin; |
|
||||||
|
|
||||||
return pg_popcount64(word); |
|
||||||
} |
|
||||||
|
|
||||||
static int |
|
||||||
pg_popcount64_builtin(uint64 word) |
|
||||||
{ |
|
||||||
#if defined(HAVE_LONG_INT_64) |
|
||||||
return __builtin_popcountl(word); |
|
||||||
#elif defined(HAVE_LONG_LONG_INT_64) |
|
||||||
return __builtin_popcountll(word); |
|
||||||
#else |
|
||||||
#error must have a working 64-bit integer datatype |
|
||||||
#endif |
|
||||||
} |
|
||||||
|
|
||||||
#else /* HAVE__BUILTIN_POPCOUNT */ |
|
||||||
/*
|
|
||||||
* pg_popcount64_slow |
|
||||||
* Return the number of 1 bits set in word |
|
||||||
*/ |
|
||||||
static int |
|
||||||
pg_popcount64_slow(uint64 word) |
|
||||||
{ |
|
||||||
int result = 0; |
|
||||||
|
|
||||||
while (word != 0) |
|
||||||
{ |
|
||||||
result += number_of_ones[word & 255]; |
|
||||||
word >>= 8; |
|
||||||
} |
|
||||||
|
|
||||||
return result; |
|
||||||
} |
|
||||||
#endif |
|
@ -1,36 +0,0 @@ |
|||||||
/*-------------------------------------------------------------------------
|
|
||||||
* |
|
||||||
* pg_bitutils_hwpopcnt.c |
|
||||||
* CPU-optimized implementation of pg_popcount variants |
|
||||||
* |
|
||||||
* This file must be compiled with a compiler-specific flag to enable the |
|
||||||
* POPCNT instruction. |
|
||||||
* |
|
||||||
* Portions Copyright (c) 2019, PostgreSQL Global Development Group |
|
||||||
* |
|
||||||
* IDENTIFICATION |
|
||||||
* src/port/pg_bitutils_hwpopcnt.c |
|
||||||
* |
|
||||||
*------------------------------------------------------------------------- |
|
||||||
*/ |
|
||||||
#include "postgres.h" |
|
||||||
|
|
||||||
#include "port/pg_bitutils.h" |
|
||||||
|
|
||||||
int |
|
||||||
pg_popcount32_hw(uint32 word) |
|
||||||
{ |
|
||||||
return __builtin_popcount(word); |
|
||||||
} |
|
||||||
|
|
||||||
int |
|
||||||
pg_popcount64_hw(uint64 word) |
|
||||||
{ |
|
||||||
#if defined(HAVE_LONG_INT_64) |
|
||||||
return __builtin_popcountl(word); |
|
||||||
#elif defined(HAVE_LONG_LONG_INT_64) |
|
||||||
return __builtin_popcountll(word); |
|
||||||
#else |
|
||||||
#error must have a working 64-bit integer datatype |
|
||||||
#endif |
|
||||||
} |
|
Loading…
Reference in new issue