From 5fdee6317bbd156a2ac48739562be109a618ccfe Mon Sep 17 00:00:00 2001
From: John Naylor <john.naylor@2ndquadrant.com>
Date: Wed, 3 Mar 2021 12:12:51 -0400
Subject: [PATCH v1 4/4] Use pg_popcount(), rather than pg_popcount{32,64}()
 where possible.

Passing a buffer is faster than passing individual words.
For the visibility map, this requires inventing a new function,
which is for demonstration and not optimized.
---
 src/backend/access/heap/visibilitymap.c | 12 +++---------
 src/backend/nodes/bitmapset.c           | 23 ++++-------------------
 src/port/pg_bitutils.c                  | 22 ++++++++++++++++++++++
 3 files changed, 29 insertions(+), 28 deletions(-)

diff --git a/src/backend/access/heap/visibilitymap.c b/src/backend/access/heap/visibilitymap.c
index e198df65d8..8747e69a2c 100644
--- a/src/backend/access/heap/visibilitymap.c
+++ b/src/backend/access/heap/visibilitymap.c
@@ -409,17 +409,11 @@ visibilitymap_count(Relation rel, BlockNumber *all_visible, BlockNumber *all_fro
 		StaticAssertStmt(MAPSIZE % sizeof(uint64) == 0,
 						 "unsupported MAPSIZE");
 		if (all_frozen == NULL)
-		{
-			for (i = 0; i < MAPSIZE / sizeof(uint64); i++)
-				nvisible += pg_popcount64(map[i] & VISIBLE_MASK64);
-		}
+			nvisible = pg_popcount_mask64(map, MAPSIZE, VISIBLE_MASK64);
 		else
 		{
-			for (i = 0; i < MAPSIZE / sizeof(uint64); i++)
-			{
-				nvisible += pg_popcount64(map[i] & VISIBLE_MASK64);
-				nfrozen += pg_popcount64(map[i] & FROZEN_MASK64);
-			}
+			nvisible = pg_popcount_mask64(map, MAPSIZE, VISIBLE_MASK64);
+			nfrozen = pg_popcount_mask64(map, MAPSIZE, FROZEN_MASK64);
 		}
 
 		ReleaseBuffer(mapBuffer);
diff --git a/src/backend/nodes/bitmapset.c b/src/backend/nodes/bitmapset.c
index 649478b0d4..5368c72255 100644
--- a/src/backend/nodes/bitmapset.c
+++ b/src/backend/nodes/bitmapset.c
@@ -452,7 +452,6 @@ bms_is_member(int x, const Bitmapset *a)
 int
 bms_member_index(Bitmapset *a, int x)
 {
-	int			i;
 	int			bitnum;
 	int			wordnum;
 	int			result = 0;
@@ -466,14 +465,8 @@ bms_member_index(Bitmapset *a, int x)
 	bitnum = BITNUM(x);
 
 	/* count bits in preceding words */
-	for (i = 0; i < wordnum; i++)
-	{
-		bitmapword	w = a->words[i];
-
-		/* No need to count the bits in a zero word */
-		if (w != 0)
-			result += bmw_popcount(w);
-	}
+	result = pg_popcount((const char *) a->words,
+						 wordnum * BITS_PER_BITMAPWORD / BITS_PER_BYTE);
 
 	/*
 	 * Now add bits of the last word, but only those before the item. We can
@@ -645,22 +638,14 @@ bms_get_singleton_member(const Bitmapset *a, int *member)
 int
 bms_num_members(const Bitmapset *a)
 {
-	int			result = 0;
 	int			nwords;
-	int			wordnum;
 
 	if (a == NULL)
 		return 0;
 	nwords = a->nwords;
-	for (wordnum = 0; wordnum < nwords; wordnum++)
-	{
-		bitmapword	w = a->words[wordnum];
 
-		/* No need to count the bits in a zero word */
-		if (w != 0)
-			result += bmw_popcount(w);
-	}
-	return result;
+	return pg_popcount((const char *) a->words,
+					   nwords * BITS_PER_BITMAPWORD / BITS_PER_BYTE);
 }
 
 /*
diff --git a/src/port/pg_bitutils.c b/src/port/pg_bitutils.c
index 33882fe175..9e3251adc8 100644
--- a/src/port/pg_bitutils.c
+++ b/src/port/pg_bitutils.c
@@ -344,3 +344,25 @@ __asm__ __volatile__(
 }
 
 #endif							/* USE_POPCNT_ASM */
+
+/*
+ * pg_popcount_mask64
+ *		Returns the number of 1-bits in buf after applying the mask
+ *
+ * Note: We currently only need a 64-bit version for the visibility map.
+ */
+uint64
+pg_popcount_mask64(const uint64 *buf, int bytes, uint64 mask)
+{
+	uint64		popcnt = 0;
+
+	Assert(bytes % sizeof(uint64) == 0);
+
+	while (bytes >= 8)
+	{
+		popcnt += pg_popcount64(*words++ & mask);
+		bytes -= 8;
+	}
+
+	return popcnt;
+}
-- 
2.22.0

