tidbitmap.c's operations loop over all the bits, but could leap over
zeros with bitmap instructions like bitmapset.c.  Hard to imagine that
matters, but I think it also comes out easier to read?
From 7eec670224270c098c2fb3ad4b7748b0769a1e95 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.mu...@gmail.com>
Date: Wed, 19 Mar 2025 02:38:26 +1300
Subject: [PATCH] Use pg_bitutils.h in tidbitmap.c.

Instead of looping over every bit, skip the zeros.
---
 src/backend/nodes/tidbitmap.c | 108 ++++++++++++++++++----------------
 1 file changed, 57 insertions(+), 51 deletions(-)

diff --git a/src/backend/nodes/tidbitmap.c b/src/backend/nodes/tidbitmap.c
index 41031aa8f2f..6ca01bdb772 100644
--- a/src/backend/nodes/tidbitmap.c
+++ b/src/backend/nodes/tidbitmap.c
@@ -44,6 +44,7 @@
 #include "common/int.h"
 #include "nodes/bitmapset.h"
 #include "nodes/tidbitmap.h"
+#include "port/pg_bitutils.h"
 #include "storage/lwlock.h"
 #include "utils/dsa.h"
 
@@ -242,6 +243,20 @@ static int	tbm_shared_comparator(const void *left, const void *right,
 #include "lib/simplehash.h"
 
 
+/*
+ * Return the position of the rightmost bit of *word, and also clear that bit.
+ * Useful for looping over the ones in a word.  *word must not be zero.
+ */
+static inline int
+bmw_pop_rightmost_one(bitmapword *word)
+{
+	int			position = bmw_rightmost_one_pos(*word);
+
+	*word &= ~((bitmapword) 1 << position);
+
+	return position;
+}
+
 /*
  * tbm_create - create an initially-empty bitmap
  *
@@ -474,24 +489,20 @@ tbm_union_page(TIDBitmap *a, const PagetableEntry *bpage)
 
 	if (bpage->ischunk)
 	{
+		BlockNumber blockno = bpage->blockno;
+
 		/* Scan b's chunk, mark each indicated page lossy in a */
 		for (wordnum = 0; wordnum < WORDS_PER_CHUNK; wordnum++)
 		{
 			bitmapword	w = bpage->words[wordnum];
 
-			if (w != 0)
+			while (w != 0)
 			{
-				BlockNumber pg;
+				int			bitnum = bmw_pop_rightmost_one(&w);
 
-				pg = bpage->blockno + (wordnum * BITS_PER_BITMAPWORD);
-				while (w != 0)
-				{
-					if (w & 1)
-						tbm_mark_page_lossy(a, pg);
-					pg++;
-					w >>= 1;
-				}
+				tbm_mark_page_lossy(a, blockno + bitnum);
 			}
+			blockno += BITS_PER_BITMAPWORD;
 		}
 	}
 	else if (tbm_page_is_lossy(a, bpage->blockno))
@@ -584,38 +595,29 @@ tbm_intersect_page(TIDBitmap *a, PagetableEntry *apage, const TIDBitmap *b)
 	{
 		/* Scan each bit in chunk, try to clear */
 		bool		candelete = true;
+		BlockNumber blockno = apage->blockno;
 
 		for (wordnum = 0; wordnum < WORDS_PER_CHUNK; wordnum++)
 		{
 			bitmapword	w = apage->words[wordnum];
+			bitmapword	neww = w;
 
-			if (w != 0)
+			while (w != 0)
 			{
-				bitmapword	neww = w;
-				BlockNumber pg;
-				int			bitnum;
+				int			bitnum = bmw_pop_rightmost_one(&w);
+				BlockNumber pg = blockno + bitnum;
 
-				pg = apage->blockno + (wordnum * BITS_PER_BITMAPWORD);
-				bitnum = 0;
-				while (w != 0)
+				if (!tbm_page_is_lossy(b, pg) &&
+					tbm_find_pageentry(b, pg) == NULL)
 				{
-					if (w & 1)
-					{
-						if (!tbm_page_is_lossy(b, pg) &&
-							tbm_find_pageentry(b, pg) == NULL)
-						{
-							/* Page is not in b at all, lose lossy bit */
-							neww &= ~((bitmapword) 1 << bitnum);
-						}
-					}
-					pg++;
-					bitnum++;
-					w >>= 1;
+					/* Page is not in b at all, lose lossy bit */
+					neww &= ~((bitmapword) 1 << bitnum);
 				}
-				apage->words[wordnum] = neww;
-				if (neww != 0)
-					candelete = false;
 			}
+			apage->words[wordnum] = neww;
+			if (neww != 0)
+				candelete = false;
+			blockno += BITS_PER_BITMAPWORD;
 		}
 		return candelete;
 	}
@@ -910,21 +912,14 @@ tbm_extract_page_tuple(TBMIterateResult *iteritem,
 	{
 		bitmapword	w = page->words[wordnum];
 
-		if (w != 0)
+		while (w != 0)
 		{
-			int			off = wordnum * BITS_PER_BITMAPWORD + 1;
+			int			bitnum = bmw_pop_rightmost_one(&w);
+			int			off = wordnum * BITS_PER_BITMAPWORD + bitnum + 1;
 
-			while (w != 0)
-			{
-				if (w & 1)
-				{
-					if (ntuples < max_offsets)
-						offsets[ntuples] = (OffsetNumber) off;
-					ntuples++;
-				}
-				off++;
-				w >>= 1;
-			}
+			if (ntuples < max_offsets)
+				offsets[ntuples] = off;
+			ntuples++;
 		}
 	}
 
@@ -938,18 +933,29 @@ static inline void
 tbm_advance_schunkbit(PagetableEntry *chunk, int *schunkbitp)
 {
 	int			schunkbit = *schunkbitp;
+	int			wordnum = WORDNUM(schunkbit);
+	int			bitnum = BITNUM(schunkbit);
+	bitmapword	w;
+
+	/* Chop off bits to the right of bitnum in starting word. */
+	w = chunk->words[wordnum] & ~((bitmapword) 0) << bitnum;
 
-	while (schunkbit < PAGES_PER_CHUNK)
+	for (;;)
 	{
-		int			wordnum = WORDNUM(schunkbit);
-		int			bitnum = BITNUM(schunkbit);
+		if (w != 0)
+		{
+			*schunkbitp =
+				wordnum * BITS_PER_BITMAPWORD + bmw_rightmost_one_pos(w);
+			return;
+		}
 
-		if ((chunk->words[wordnum] & ((bitmapword) 1 << bitnum)) != 0)
+		if (++wordnum == WORDS_PER_CHUNK)
 			break;
-		schunkbit++;
+		w = chunk->words[wordnum];
 	}
 
-	*schunkbitp = schunkbit;
+	/* No bits found.  Point past end. */
+	*schunkbitp = WORDS_PER_CHUNK * BITS_PER_BITMAPWORD;
 }
 
 /*
-- 
2.39.5

Reply via email to