diff -Nru old/config/c-compiler.m4 new/config/c-compiler.m4
--- a/config/c-compiler.m4	2026-11-02 16:38:41.810155094 +0800
+++ b/config/c-compiler.m4	2026-11-02 16:38:41.814155136 +0800
@@ -662,6 +662,39 @@
 undefine([Ac_cachevar])dnl
 ])# PGAC_ARMV8_CRC32C_INTRINSICS
 
+# PGAC_RISCV_ZBC_CRC32C_INTRINSICS
+# ----------------------------
+# Check if the compiler supports the CRC32C computation using the
+# __builtin_rev_crc32_data8, __builtin_rev_crc32_data16 and
+# __builtin_rev_crc32_data32 intrinsic functions.  These expand to
+# clmul-based code sequences on targets with the RISC-V Zbc
+# carry-less multiplication extension.
+#
+# An optional compiler flag can be passed as argument (e.g.
+# -march=rv64gc_zbc). If the intrinsics are supported, sets
+# pgac_riscv_zbc_crc32c_intrinsics, and CFLAGS_CRC.
+AC_DEFUN([PGAC_RISCV_ZBC_CRC32C_INTRINSICS],
+[define([Ac_cachevar], [AS_TR_SH([pgac_cv_riscv_zbc_crc32c_intrinsics_$1])])dnl
+AC_CACHE_CHECK([for __builtin_rev_crc32_data8, __builtin_rev_crc32_data16, and __builtin_rev_crc32_data32 with CFLAGS=$1], [Ac_cachevar],
+[pgac_save_CFLAGS=$CFLAGS
+CFLAGS="$pgac_save_CFLAGS $1"
+AC_LINK_IFELSE([AC_LANG_PROGRAM([],
+  [unsigned int crc = 0;
+   crc = __builtin_rev_crc32_data8(crc, 0, 0x1EDC6F41);
+   crc = __builtin_rev_crc32_data16(crc, 0, 0x1EDC6F41);
+   crc = __builtin_rev_crc32_data32(crc, 0, 0x1EDC6F41);
+   /* return computed value, to prevent the above being optimized away */
+   return crc == 0;])],
+  [Ac_cachevar=yes],
+  [Ac_cachevar=no])
+CFLAGS="$pgac_save_CFLAGS"])
+if test x"$Ac_cachevar" = x"yes"; then
+  CFLAGS_CRC="$1"
+  pgac_riscv_zbc_crc32c_intrinsics=yes
+fi
+undefine([Ac_cachevar])dnl
+])# PGAC_RISCV_ZBC_CRC32C_INTRINSICS
+
 # PGAC_LOONGARCH_CRC32C_INTRINSICS
 # ---------------------------
 # Check if the compiler supports the LoongArch CRCC instructions, using
diff -Nru old/configure.ac new/configure.ac
--- a/configure.ac	2026-11-02 16:38:41.814155136 +0800
+++ b/configure.ac	2026-11-02 16:38:41.814155136 +0800
@@ -2154,6 +2154,16 @@
 # with the default compiler flags.
 PGAC_LOONGARCH_CRC32C_INTRINSICS()
 
+# Check for RISC-V Zbc intrinsics to do CRC calculations.
+#
+# First check if __builtin_rev_crc32_data* intrinsics can be used with the
+# default compiler flags. If not, check if adding "-march=rv64gc_zbc" flag
+# helps. CFLAGS_CRC is set if the extra flag is required.
+PGAC_RISCV_ZBC_CRC32C_INTRINSICS([])
+if test x"$pgac_riscv_zbc_crc32c_intrinsics" != x"yes"; then
+  PGAC_RISCV_ZBC_CRC32C_INTRINSICS([-march=rv64gc_zbc])
+fi
+
 AC_SUBST(CFLAGS_CRC)
 
 # Select CRC-32C implementation.
@@ -2175,7 +2185,7 @@
 #
 # If we are targeting a LoongArch processor, CRC instructions are
 # always available (at least on 64 bit), so no runtime check is needed.
-if test x"$USE_SLICING_BY_8_CRC32C" = x"" && test x"$USE_SSE42_CRC32C" = x"" && test x"$USE_SSE42_CRC32C_WITH_RUNTIME_CHECK" = x"" && test x"$USE_ARMV8_CRC32C" = x"" && test x"$USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK" = x"" && test x"$USE_LOONGARCH_CRC32C" = x""; then
+if test x"$USE_SLICING_BY_8_CRC32C" = x"" && test x"$USE_SSE42_CRC32C" = x"" && test x"$USE_SSE42_CRC32C_WITH_RUNTIME_CHECK" = x"" && test x"$USE_ARMV8_CRC32C" = x"" && test x"$USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK" = x"" && test x"$USE_LOONGARCH_CRC32C" = x"" && test x"$USE_ZBC_CRC32C_WITH_RUNTIME_CHECK" = x""; then
   # Use Intel SSE 4.2 if available.
   if test x"$pgac_sse42_crc32_intrinsics" = x"yes" && test x"$SSE4_2_TARGETED" = x"1" ; then
     USE_SSE42_CRC32C=1
@@ -2197,9 +2207,14 @@
           if test x"$pgac_loongarch_crc32c_intrinsics" = x"yes"; then
             USE_LOONGARCH_CRC32C=1
           else
-            # fall back to slicing-by-8 algorithm, which doesn't require any
-            # special CPU support.
-            USE_SLICING_BY_8_CRC32C=1
+            # RISC-V Zbc, with runtime check?
+            if test x"$pgac_riscv_zbc_crc32c_intrinsics" = x"yes"; then
+              USE_ZBC_CRC32C_WITH_RUNTIME_CHECK=1
+            else
+              # fall back to slicing-by-8 algorithm, which doesn't require any
+              # special CPU support.
+              USE_SLICING_BY_8_CRC32C=1
+            fi
           fi
         fi
       fi
@@ -2234,9 +2249,15 @@
           PG_CRC32C_OBJS="pg_crc32c_loongarch.o"
           AC_MSG_RESULT(LoongArch CRCC instructions)
         else
-          AC_DEFINE(USE_SLICING_BY_8_CRC32C, 1, [Define to 1 to use software CRC-32C implementation (slicing-by-8).])
-          PG_CRC32C_OBJS="pg_crc32c_sb8.o"
-          AC_MSG_RESULT(slicing-by-8)
+          if test x"$USE_ZBC_CRC32C_WITH_RUNTIME_CHECK" = x"1"; then
+            AC_DEFINE(USE_ZBC_CRC32C_WITH_RUNTIME_CHECK, 1, [Define to 1 to use RISC-V Zbc clmul instructions with a runtime check.])
+            PG_CRC32C_OBJS="pg_crc32c_zbc.o pg_crc32c_sb8.o pg_crc32c_zbc_choose.o"
+            AC_MSG_RESULT(RISC-V Zbc clmul instructions with runtime check)
+          else
+            AC_DEFINE(USE_SLICING_BY_8_CRC32C, 1, [Define to 1 to use software CRC-32C implementation (slicing-by-8).])
+            PG_CRC32C_OBJS="pg_crc32c_sb8.o"
+            AC_MSG_RESULT(slicing-by-8)
+          fi
         fi
       fi
     fi
diff -Nru old/src/include/pg_config.h.in new/src/include/pg_config.h.in
--- a/src/include/pg_config.h.in	2026-11-02 16:38:41.814155136 +0800
+++ b/src/include/pg_config.h.in	2026-11-02 16:38:41.818155178 +0800
@@ -756,6 +756,9 @@
 /* Define to select Win32-style shared memory. */
 #undef USE_WIN32_SHARED_MEMORY
 
+/* Define to 1 to use RISC-V Zbc clmul instructions with a runtime check. */
+#undef USE_ZBC_CRC32C_WITH_RUNTIME_CHECK
+
 /* Define to 1 to build with ZSTD support. (--with-zstd) */
 #undef USE_ZSTD
 
diff -Nru old/src/include/port/pg_crc32c.h new/src/include/port/pg_crc32c.h
--- a/src/include/port/pg_crc32c.h	2026-11-02 16:38:41.818155178 +0800
+++ b/src/include/port/pg_crc32c.h	2026-11-02 16:38:41.818155178 +0800
@@ -67,7 +67,7 @@
 
 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)
+#elif defined(USE_SSE42_CRC32C_WITH_RUNTIME_CHECK) || defined(USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK) || defined(USE_ZBC_CRC32C_WITH_RUNTIME_CHECK)
 
 /*
  * Use Intel SSE 4.2 or ARMv8 instructions, but perform a runtime check first
@@ -86,6 +86,9 @@
 #ifdef USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK
 extern pg_crc32c pg_comp_crc32c_armv8(pg_crc32c crc, const void *data, size_t len);
 #endif
+#ifdef USE_ZBC_CRC32C_WITH_RUNTIME_CHECK
+extern pg_crc32c pg_comp_crc32c_zbc(pg_crc32c crc, const void *data, size_t len);
+#endif
 
 #else
 /*
diff -Nru old/src/port/Makefile new/src/port/Makefile
--- a/src/port/Makefile	2026-11-02 16:40:43.675421867 +0800
+++ b/src/port/Makefile	2026-11-02 16:40:43.675421867 +0800
@@ -93,6 +93,11 @@
 pg_crc32c_armv8_shlib.o: CFLAGS+=$(CFLAGS_CRC)
 pg_crc32c_armv8_srv.o: CFLAGS+=$(CFLAGS_CRC)
 
+# all versions of pg_crc32c_zbc.o need CFLAGS_CRC
+pg_crc32c_zbc.o: CFLAGS+=$(CFLAGS_CRC)
+pg_crc32c_zbc_shlib.o: CFLAGS+=$(CFLAGS_CRC)
+pg_crc32c_zbc_srv.o: CFLAGS+=$(CFLAGS_CRC)
+
 # all versions of pg_popcount_avx512_choose.o need CFLAGS_XSAVE
 pg_popcount_avx512_choose.o: CFLAGS+=$(CFLAGS_XSAVE)
 pg_popcount_avx512_choose_shlib.o: CFLAGS+=$(CFLAGS_XSAVE)
diff -Nru old/src/port/pg_crc32c_zbc.c new/src/port/pg_crc32c_zbc.c
--- a/src/port/pg_crc32c_zbc.c	1970-01-01 08:00:00.000000000 +0800
+++ b/src/port/pg_crc32c_zbc.c	2026-11-02 16:40:43.679421909 +0800
@@ -0,0 +1,71 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_crc32c_zbc.c
+ *	  Compute CRC-32C checksum using RISC-V Zbc carry-less multiplication
+ *	  instructions
+ *
+ * Uses the compiler builtins __builtin_rev_crc32_data{8,16,32}(), which
+ * expand to clmul/clmulh sequences on targets with the Zbc extension.
+ * The polynomial argument is the normal (non-reflected) representation of
+ * the Castagnoli polynomial, 0x1EDC6F41.
+ *
+ * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/port/pg_crc32c_zbc.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "c.h"
+
+#include "port/pg_crc32c.h"
+
+#define CRC32C_POLY 0x1EDC6F41
+
+pg_crc32c
+pg_comp_crc32c_zbc(pg_crc32c crc, const void *data, size_t len)
+{
+	const unsigned char *p = data;
+	const unsigned char *pend = p + len;
+
+	/*
+	 * Process leading bytes one at a time, so that the loop below starts
+	 * with a pointer aligned to eight bytes.
+	 */
+	while (p < pend && ((uintptr_t) p & 7))
+	{
+		crc = __builtin_rev_crc32_data8(crc, *p++, CRC32C_POLY);
+	}
+
+	/* Process eight bytes at a time. */
+	while (p + 8 <= pend)
+	{
+		crc = __builtin_rev_crc32_data32(crc, ((const uint32_t *) p)[0],
+										 CRC32C_POLY);
+		crc = __builtin_rev_crc32_data32(crc, ((const uint32_t *) p)[1],
+										 CRC32C_POLY);
+		p += 8;
+	}
+
+	/* Process remaining 0-7 bytes. */
+	if (p + 4 <= pend)
+	{
+		crc = __builtin_rev_crc32_data32(crc, *(const uint32_t *) p,
+										 CRC32C_POLY);
+		p += 4;
+	}
+	if (p + 2 <= pend)
+	{
+		crc = __builtin_rev_crc32_data16(crc, *(const uint16 *) p,
+										 CRC32C_POLY);
+		p += 2;
+	}
+	if (p < pend)
+	{
+		crc = __builtin_rev_crc32_data8(crc, *p, CRC32C_POLY);
+	}
+
+	return crc;
+}
diff -Nru old/src/port/pg_crc32c_zbc_choose.c new/src/port/pg_crc32c_zbc_choose.c
--- a/src/port/pg_crc32c_zbc_choose.c	1970-01-01 08:00:00.000000000 +0800
+++ b/src/port/pg_crc32c_zbc_choose.c	2026-11-02 16:40:43.679421909 +0800
@@ -0,0 +1,100 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_crc32c_zbc_choose.c
+ *	  Choose between Zbc and software CRC-32C implementation.
+ *
+ * On first call, checks if the CPU we're running on supports the Zbc
+ * carry-less multiplication extension. If it does, use the clmul-based
+ * implementation for CRC-32C computation. Otherwise, fall back to the pure
+ * software implementation (slicing-by-8).
+ *
+ * The Zbc extension has no bit in the auxiliary vector, so like the ARMv8
+ * implementation, we probe by trying to execute the clmul-based code.  If
+ * the instructions are not available, we expect to get SIGILL, which we can
+ * trap.
+ *
+ * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/port/pg_crc32c_zbc_choose.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+#include <setjmp.h>
+#include <signal.h>
+
+#include "port/pg_crc32c.h"
+
+
+static sigjmp_buf illegal_instruction_jump;
+
+/*
+ * Probe by trying to execute pg_comp_crc32c_zbc().  If the instructions
+ * aren't available, we expect to get SIGILL, which we can trap.
+ */
+static void
+illegal_instruction_handler(SIGNAL_ARGS)
+{
+	siglongjmp(illegal_instruction_jump, 1);
+}
+
+static bool
+pg_crc32c_zbc_available(void)
+{
+	uint64		data = 42;
+	int			result;
+
+	/*
+	 * Be careful not to do anything that might throw an error while we have
+	 * the SIGILL handler set to a nonstandard value.
+	 */
+	pqsignal(SIGILL, illegal_instruction_handler);
+	if (sigsetjmp(illegal_instruction_jump, 1) == 0)
+	{
+		/* Rather than hard-wiring an expected result, compare to SB8 code */
+		result = (pg_comp_crc32c_zbc(0, &data, sizeof(data)) ==
+				  pg_comp_crc32c_sb8(0, &data, sizeof(data)));
+	}
+	else
+	{
+		/* We got the SIGILL trap */
+		result = -1;
+	}
+	pqsignal(SIGILL, SIG_DFL);
+
+#ifndef FRONTEND
+	/* We don't expect this case, so complain loudly */
+	if (result == 0)
+		elog(ERROR, "crc32 hardware and software results disagree");
+
+	elog(DEBUG1, "using zbc crc32 clmul = %d", (result > 0));
+#endif
+
+	return (result > 0);
+}
+
+/*
+ * This gets called on the first call. It replaces the function pointer
+ * so that subsequent calls are routed directly to the chosen implementation.
+ */
+static pg_crc32c
+pg_comp_crc32c_choose(pg_crc32c crc, const void *data, size_t len)
+{
+	if (pg_crc32c_zbc_available())
+		pg_comp_crc32c = pg_comp_crc32c_zbc;
+	else
+		pg_comp_crc32c = pg_comp_crc32c_sb8;
+
+	return pg_comp_crc32c(crc, data, len);
+}
+
+pg_crc32c	(*pg_comp_crc32c) (pg_crc32c crc, const void *data, size_t len) = pg_comp_crc32c_choose;
