diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/include/pg_config.h.in | 3 | ||||
-rw-r--r-- | src/include/port/pg_crc32c.h | 9 | ||||
-rw-r--r-- | src/port/meson.build | 3 | ||||
-rw-r--r-- | src/port/pg_crc32c_loongarch.c | 73 |
4 files changed, 88 insertions, 0 deletions
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index ee209d6d702..d8a2985567f 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -714,6 +714,9 @@ /* Define to 1 to build with LLVM based JIT support. (--with-llvm) */ #undef USE_LLVM +/* Define to 1 to use LoongArch CRCC instructions. */ +#undef USE_LOONGARCH_CRC32C + /* Define to 1 to build with LZ4 support. (--with-lz4) */ #undef USE_LZ4 diff --git a/src/include/port/pg_crc32c.h b/src/include/port/pg_crc32c.h index 7f8779261c3..d085f1dc00b 100644 --- a/src/include/port/pg_crc32c.h +++ b/src/include/port/pg_crc32c.h @@ -58,6 +58,15 @@ extern pg_crc32c pg_comp_crc32c_sse42(pg_crc32c crc, const void *data, size_t le extern pg_crc32c pg_comp_crc32c_armv8(pg_crc32c crc, const void *data, size_t len); +#elif defined(USE_LOONGARCH_CRC32C) +/* Use LoongArch CRCC instructions. */ + +#define COMP_CRC32C(crc, data, len) \ + ((crc) = pg_comp_crc32c_loongarch((crc), (data), (len))) +#define FIN_CRC32C(crc) ((crc) ^= 0xFFFFFFFF) + +extern pg_crc32c pg_comp_crc32c_loongarch(pg_crc32c crc, const void *data, size_t len); + #elif defined(USE_SSE42_CRC32C_WITH_RUNTIME_CHECK) || defined(USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK) /* diff --git a/src/port/meson.build b/src/port/meson.build index 9d0cd93c438..deb354418db 100644 --- a/src/port/meson.build +++ b/src/port/meson.build @@ -92,6 +92,9 @@ replace_funcs_pos = [ ['pg_crc32c_armv8_choose', 'USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK'], ['pg_crc32c_sb8', 'USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK'], + # loongarch + ['pg_crc32c_loongarch', 'USE_LOONGARCH_CRC32C'], + # generic fallback ['pg_crc32c_sb8', 'USE_SLICING_BY_8_CRC32C'], ] diff --git a/src/port/pg_crc32c_loongarch.c b/src/port/pg_crc32c_loongarch.c new file mode 100644 index 00000000000..db9da80e1bf --- /dev/null +++ b/src/port/pg_crc32c_loongarch.c @@ -0,0 +1,73 @@ +/*------------------------------------------------------------------------- + * + * pg_crc32c_loongarch.c + * Compute CRC-32C checksum using LoongArch CRCC instructions + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/port/pg_crc32c_loongarch.c + * + *------------------------------------------------------------------------- + */ +#include "c.h" + +#include "port/pg_crc32c.h" + +pg_crc32c +pg_comp_crc32c_loongarch(pg_crc32c crc, const void *data, size_t len) +{ + const unsigned char *p = data; + const unsigned char *pend = p + len; + + /* + * LoongArch doesn't require alignment, but aligned memory access is + * significantly faster. Process leading bytes so that the loop below + * starts with a pointer aligned to eight bytes. + */ + if (!PointerIsAligned(p, uint16) && + p + 1 <= pend) + { + crc = __builtin_loongarch_crcc_w_b_w(*p, crc); + p += 1; + } + if (!PointerIsAligned(p, uint32) && + p + 2 <= pend) + { + crc = __builtin_loongarch_crcc_w_h_w(*(uint16 *) p, crc); + p += 2; + } + if (!PointerIsAligned(p, uint64) && + p + 4 <= pend) + { + crc = __builtin_loongarch_crcc_w_w_w(*(uint32 *) p, crc); + p += 4; + } + + /* Process eight bytes at a time, as far as we can. */ + while (p + 8 <= pend) + { + crc = __builtin_loongarch_crcc_w_d_w(*(uint64 *) p, crc); + p += 8; + } + + /* Process remaining 0-7 bytes. */ + if (p + 4 <= pend) + { + crc = __builtin_loongarch_crcc_w_w_w(*(uint32 *) p, crc); + p += 4; + } + if (p + 2 <= pend) + { + crc = __builtin_loongarch_crcc_w_h_w(*(uint16 *) p, crc); + p += 2; + } + if (p < pend) + { + crc = __builtin_loongarch_crcc_w_b_w(*p, crc); + } + + return crc; +} |