From 204b0cbecb82ab3fde2e12998a89e7227cd64094 Mon Sep 17 00:00:00 2001
From: John Naylor <john.naylor@postgresql.org>
Date: Tue, 24 Jan 2023 14:39:26 +0700
Subject: [PATCH] Add assert checking to pg_leftmost_one_pos32() and friends

Discussion: https://www.postgresql.org/message-id/CAFBsxsEPc%2BFnX_0vmmQ5DHv60sk4rL_RZJ%2BMD6ei%3D76L0kFMvA%40mail.gmail.com
---
 src/include/port/pg_bitutils.h | 86 ++++++++++++++++++++++++----------
 1 file changed, 60 insertions(+), 26 deletions(-)

diff --git a/src/include/port/pg_bitutils.h b/src/include/port/pg_bitutils.h
index a49a9c03d9..a5df4f1a35 100644
--- a/src/include/port/pg_bitutils.h
+++ b/src/include/port/pg_bitutils.h
@@ -26,10 +26,11 @@ static inline int
 pg_leftmost_one_pos32(uint32 word)
 {
 #ifdef HAVE__BUILTIN_CLZ
-	Assert(word != 0);
+	int			bitscan_result;
+#endif
 
-	return 31 - __builtin_clz(word);
-#else
+#if !defined(HAVE__BUILTIN_CLZ) || defined(USE_ASSERT_CHECKING)
+	int			result;
 	int			shift = 32 - 8;
 
 	Assert(word != 0);
@@ -37,7 +38,15 @@ pg_leftmost_one_pos32(uint32 word)
 	while ((word >> shift) == 0)
 		shift -= 8;
 
-	return shift + pg_leftmost_one_pos[(word >> shift) & 255];
+	result = shift + pg_leftmost_one_pos[(word >> shift) & 255];
+#endif
+
+#if defined(HAVE__BUILTIN_CLZ)
+	bitscan_result = 31 - __builtin_clz(word);
+	Assert(bitscan_result == result);
+	return bitscan_result;
+#else
+	return result;
 #endif							/* HAVE__BUILTIN_CLZ */
 }
 
@@ -49,16 +58,11 @@ static inline int
 pg_leftmost_one_pos64(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
+	int			bitscan_result;
 #endif
-#else							/* !HAVE__BUILTIN_CLZ */
+
+#if !defined(HAVE__BUILTIN_CLZ) || defined(USE_ASSERT_CHECKING)
+	int			result;
 	int			shift = 64 - 8;
 
 	Assert(word != 0);
@@ -66,7 +70,21 @@ pg_leftmost_one_pos64(uint64 word)
 	while ((word >> shift) == 0)
 		shift -= 8;
 
-	return shift + pg_leftmost_one_pos[(word >> shift) & 255];
+	result = shift + pg_leftmost_one_pos[(word >> shift) & 255];
+#endif
+
+#if defined(HAVE__BUILTIN_CLZ)
+#if defined(HAVE_LONG_INT_64)
+	bitscan_result = 63 - __builtin_clzl(word);
+#elif defined(HAVE_LONG_LONG_INT_64)
+	bitscan_result = 63 - __builtin_clzll(word);
+#else
+#error must have a working 64-bit integer datatype
+#endif							/* HAVE_LONG_INT_64 */
+	Assert(bitscan_result == result);
+	return bitscan_result;
+#else
+	return result;
 #endif							/* HAVE__BUILTIN_CLZ */
 }
 
@@ -79,10 +97,11 @@ static inline int
 pg_rightmost_one_pos32(uint32 word)
 {
 #ifdef HAVE__BUILTIN_CTZ
-	Assert(word != 0);
+	const uint32 orig_word = word;
+	int			bitscan_result;
+#endif
 
-	return __builtin_ctz(word);
-#else
+#if !defined(HAVE__BUILTIN_CTZ) || defined(USE_ASSERT_CHECKING)
 	int			result = 0;
 
 	Assert(word != 0);
@@ -93,6 +112,13 @@ pg_rightmost_one_pos32(uint32 word)
 		result += 8;
 	}
 	result += pg_rightmost_one_pos[word & 255];
+#endif
+
+#if defined(HAVE__BUILTIN_CTZ)
+	bitscan_result = __builtin_ctz(orig_word);
+	Assert(bitscan_result == result);
+	return bitscan_result;
+#else
 	return result;
 #endif							/* HAVE__BUILTIN_CTZ */
 }
@@ -105,16 +131,11 @@ static inline int
 pg_rightmost_one_pos64(uint64 word)
 {
 #ifdef HAVE__BUILTIN_CTZ
-	Assert(word != 0);
-
-#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
+	const uint64 orig_word = word;
+	int			bitscan_result;
 #endif
-#else							/* !HAVE__BUILTIN_CTZ */
+
+#if !defined(HAVE__BUILTIN_CTZ) || defined(USE_ASSERT_CHECKING)
 	int			result = 0;
 
 	Assert(word != 0);
@@ -125,6 +146,19 @@ pg_rightmost_one_pos64(uint64 word)
 		result += 8;
 	}
 	result += pg_rightmost_one_pos[word & 255];
+#endif
+
+#if defined(HAVE__BUILTIN_CTZ)
+#if defined(HAVE_LONG_INT_64)
+	bitscan_result = __builtin_ctzl(orig_word);
+#elif defined(HAVE_LONG_LONG_INT_64)
+	bitscan_result = __builtin_ctzll(orig_word);
+#else
+#error must have a working 64-bit integer datatype
+#endif							/* HAVE_LONG_INT_64 */
+	Assert(bitscan_result == result);
+	return bitscan_result;
+#else
 	return result;
 #endif							/* HAVE__BUILTIN_CTZ */
 }