From 2bf6c7508ca013b9c45c6bee0168ce01ff1ea8bc Mon Sep 17 00:00:00 2001 From: Andres Freund Date: Wed, 20 Sep 2017 14:04:06 -0700 Subject: [PATCH] Extend & revamp pg_bswap.h infrastructure. Upcoming patches are going to address performance issues that involve slow system provided ntohs/htons etc. To address that expand pg_bswap.h to provide pg_ntohs/l/ll, pg_htons/l/ll and optimize their respective implementations by falling back to compiler intrinsics for gcc compatible compilers and msvc. Additionally remove multiple evaluation hazards from the existing BSWAP32/64 macros, by replacing them with inline functions when necessary. In the course of that the naming scheme is changed to pg_bswap16/32/64. Author: Andres Freund --- config/c-compiler.m4 | 17 ++++++ contrib/btree_gist/btree_uuid.c | 4 +- src/include/port/pg_bswap.h | 132 ++++++++++++++++++++++++++++++++-------- src/include/port/pg_crc32c.h | 2 +- 4 files changed, 128 insertions(+), 27 deletions(-) diff --git a/config/c-compiler.m4 b/config/c-compiler.m4 index 7275ea69fe..3a4498fec4 100644 --- a/config/c-compiler.m4 +++ b/config/c-compiler.m4 @@ -224,6 +224,23 @@ AC_DEFINE(HAVE__BUILTIN_TYPES_COMPATIBLE_P, 1, fi])# PGAC_C_TYPES_COMPATIBLE +# PGAC_C_BUILTIN_BSWAP16 +# ------------------------- +# Check if the C compiler understands __builtin_bswap16(), +# and define HAVE__BUILTIN_BSWAP16 if so. +AC_DEFUN([PGAC_C_BUILTIN_BSWAP16], +[AC_CACHE_CHECK(for __builtin_bswap16, pgac_cv__builtin_bswap16, +[AC_COMPILE_IFELSE([AC_LANG_SOURCE( +[static unsigned long int x = __builtin_bswap16(0xaabb);] +)], +[pgac_cv__builtin_bswap16=yes], +[pgac_cv__builtin_bswap16=no])]) +if test x"$pgac_cv__builtin_bswap16" = xyes ; then +AC_DEFINE(HAVE__BUILTIN_BSWAP16, 1, + [Define to 1 if your compiler understands __builtin_bswap16.]) +fi])# PGAC_C_BUILTIN_BSWAP16 + + # PGAC_C_BUILTIN_BSWAP32 # ------------------------- diff --git a/contrib/btree_gist/btree_uuid.c b/contrib/btree_gist/btree_uuid.c index ecf357d662..9ff421ea55 100644 --- a/contrib/btree_gist/btree_uuid.c +++ b/contrib/btree_gist/btree_uuid.c @@ -182,8 +182,8 @@ uuid_2_double(const pg_uuid_t *u) * machine, byte-swap each half so we can use native uint64 arithmetic. */ #ifndef WORDS_BIGENDIAN - uu[0] = BSWAP64(uu[0]); - uu[1] = BSWAP64(uu[1]); + uu[0] = pg_bswap64(uu[0]); + uu[1] = pg_bswap64(uu[1]); #endif /* diff --git a/src/include/port/pg_bswap.h b/src/include/port/pg_bswap.h index 50a6bd106b..3d10aa247b 100644 --- a/src/include/port/pg_bswap.h +++ b/src/include/port/pg_bswap.h @@ -3,15 +3,13 @@ * pg_bswap.h * Byte swapping. * - * Macros for reversing the byte order of 32-bit and 64-bit unsigned integers. + * Macros for reversing the byte order of 16, 32 and 64-bit unsigned integers. * For example, 0xAABBCCDD becomes 0xDDCCBBAA. These are just wrappers for * built-in functions provided by the compiler where support exists. - * Elsewhere, beware of multiple evaluations of the arguments! * - * Note that the GCC built-in functions __builtin_bswap32() and - * __builtin_bswap64() are documented as accepting single arguments of type - * uint32_t and uint64_t respectively (these are also the respective return - * types). Use caution when using these wrapper macros with signed integers. + * Note that all of these functions accept unsigned integers as arguments and + * return the same. Use caution when using these wrapper macros with signed + * integers. * * Copyright (c) 2015-2017, PostgreSQL Global Development Group * @@ -22,28 +20,114 @@ #ifndef PG_BSWAP_H #define PG_BSWAP_H -#ifdef HAVE__BUILTIN_BSWAP32 -#define BSWAP32(x) __builtin_bswap32(x) + +/* In all supported versions msvc provides _byteswap_* functions in stdlib.h */ +#ifdef _MSC_VER +#include +#endif + + +/* implementation of uint16 pg_bswap16(uint16) */ +#if defined(HAVE__BUILTIN_BSWAP16) + +#define pg_bswap16(x) __builtin_bswap16(x) + +#elif defined(_MSC_VER) + +#define pg_bswap16(x) _byteswap_ushort(x) + #else -#define BSWAP32(x) ((((x) << 24) & 0xff000000) | \ - (((x) << 8) & 0x00ff0000) | \ - (((x) >> 8) & 0x0000ff00) | \ - (((x) >> 24) & 0x000000ff)) + +static inline uint16 +pg_bswap16(uint16 x) +{ + return + ((x << 8) & 0xff00) | + ((x >> 8) & 0x00ff); +} + +#endif /* HAVE__BUILTIN_BSWAP16 */ + + +/* implementation of uint32 pg_bswap32(uint32) */ +#if defined(HAVE__BUILTIN_BSWAP32) + +#define pg_bswap32(x) __builtin_bswap32(x) + +#elif defined(_MSC_VER) + +#define pg_bswap32(x) _byteswap_ulong(x) + +#else + +static inline uint32 +pg_bswap32(uint32 x) +{ + return + ((x << 24) & 0xff000000) | + ((x << 8) & 0x00ff0000) | + ((x >> 8) & 0x0000ff00) | + ((x >> 24) & 0x000000ff); +} + #endif /* HAVE__BUILTIN_BSWAP32 */ -#ifdef HAVE__BUILTIN_BSWAP64 -#define BSWAP64(x) __builtin_bswap64(x) + +/* implementation of uint64 pg_bswap64(uint64) */ +#if defined(HAVE__BUILTIN_BSWAP64) + +#define pg_bswap64(x) __builtin_bswap64(x) + + +#elif defined(_MSC_VER) + +#define pg_bswap64(x) _byteswap_uint64(x) + #else -#define BSWAP64(x) ((((x) << 56) & UINT64CONST(0xff00000000000000)) | \ - (((x) << 40) & UINT64CONST(0x00ff000000000000)) | \ - (((x) << 24) & UINT64CONST(0x0000ff0000000000)) | \ - (((x) << 8) & UINT64CONST(0x000000ff00000000)) | \ - (((x) >> 8) & UINT64CONST(0x00000000ff000000)) | \ - (((x) >> 24) & UINT64CONST(0x0000000000ff0000)) | \ - (((x) >> 40) & UINT64CONST(0x000000000000ff00)) | \ - (((x) >> 56) & UINT64CONST(0x00000000000000ff))) + +static inline uint16 +pg_bswap64(uint16 x) +{ + return + ((x << 56) & UINT64CONST(0xff00000000000000)) | + ((x << 40) & UINT64CONST(0x00ff000000000000)) | + ((x << 24) & UINT64CONST(0x0000ff0000000000)) | + ((x << 8) & UINT64CONST(0x000000ff00000000)) | + ((x >> 8) & UINT64CONST(0x00000000ff000000)) | + ((x >> 24) & UINT64CONST(0x0000000000ff0000)) | + ((x >> 40) & UINT64CONST(0x000000000000ff00)) | + ((x >> 56) & UINT64CONST(0x00000000000000ff)); +} #endif /* HAVE__BUILTIN_BSWAP64 */ + +/* + * Portable and fast equivalents for for ntohs, ntohl, htons, htonl, + * additionally extended to 64 bits. + */ +#ifdef WORDS_BIGENDIAN + +#define pg_htons(x) (x) +#define pg_htonl(x) (x) +#define pg_htonll(x) (x) + +#define pg_ntohs(x) (x) +#define pg_ntohl(x) (x) +#define pg_ntohll(x) (x) + +#else + +#define pg_htons(x) pg_bswap16(x) +#define pg_htonl(x) pg_bswap32(x) +#define pg_htonll(x) pg_bswap64(x) + +#define pg_ntohs(x) pg_bswap16(x) +#define pg_ntohl(x) pg_bswap32(x) +#define pg_ntohll(x) pg_bswap64(x) + +#endif /* WORDS_BIGENDIAN */ + + /* * Rearrange the bytes of a Datum from big-endian order into the native byte * order. On big-endian machines, this does nothing at all. Note that the C @@ -60,9 +144,9 @@ #define DatumBigEndianToNative(x) (x) #else /* !WORDS_BIGENDIAN */ #if SIZEOF_DATUM == 8 -#define DatumBigEndianToNative(x) BSWAP64(x) +#define DatumBigEndianToNative(x) pg_bswap64(x) #else /* SIZEOF_DATUM != 8 */ -#define DatumBigEndianToNative(x) BSWAP32(x) +#define DatumBigEndianToNative(x) pg_bswap32(x) #endif /* SIZEOF_DATUM == 8 */ #endif /* WORDS_BIGENDIAN */ diff --git a/src/include/port/pg_crc32c.h b/src/include/port/pg_crc32c.h index cd58ecc988..32d7176273 100644 --- a/src/include/port/pg_crc32c.h +++ b/src/include/port/pg_crc32c.h @@ -73,7 +73,7 @@ extern pg_crc32c (*pg_comp_crc32c) (pg_crc32c crc, const void *data, size_t len) #define COMP_CRC32C(crc, data, len) \ ((crc) = pg_comp_crc32c_sb8((crc), (data), (len))) #ifdef WORDS_BIGENDIAN -#define FIN_CRC32C(crc) ((crc) = BSWAP32(crc) ^ 0xFFFFFFFF) +#define FIN_CRC32C(crc) ((crc) = pg_bswap32(crc) ^ 0xFFFFFFFF) #else #define FIN_CRC32C(crc) ((crc) ^= 0xFFFFFFFF) #endif -- 2.14.1.536.g6867272d5b.dirty