From e31a67e4b09a20d6c1922cfe9e729c08e50ffad4 Mon Sep 17 00:00:00 2001
From: Yuya Watari <watari.yuya@gmail.com>
Date: Tue, 14 Mar 2023 15:12:18 +0900
Subject: [PATCH v1] Remove bms_is_empty_internal() function calls

Originally, we checked whether the result of the Bitmapset operation
was empty or not by calling the bms_is_empty_internal() function.
However, these calls lead to unnecessary looping over the result
Bitmapset. This commit reduces such redundant calls and improves the
performance.
---
 src/backend/nodes/bitmapset.c | 78 ++++++++++++++++++++---------------
 1 file changed, 44 insertions(+), 34 deletions(-)

diff --git a/src/backend/nodes/bitmapset.c b/src/backend/nodes/bitmapset.c
index 7ba3cf635b..b8155ae869 100644
--- a/src/backend/nodes/bitmapset.c
+++ b/src/backend/nodes/bitmapset.c
@@ -64,8 +64,6 @@
 #error "invalid BITS_PER_BITMAPWORD"
 #endif
 
-static bool bms_is_empty_internal(const Bitmapset *a);
-
 
 /*
  * bms_copy - make a palloc'd copy of a bitmapset
@@ -263,6 +261,7 @@ bms_intersect(const Bitmapset *a, const Bitmapset *b)
 	const Bitmapset *other;
 	int			resultlen;
 	int			i;
+	bitmapword	bitwise_or = 0;
 
 	/* Handle cases where either input is NULL */
 	if (a == NULL || b == NULL)
@@ -281,9 +280,17 @@ bms_intersect(const Bitmapset *a, const Bitmapset *b)
 	/* And intersect the longer input with the result */
 	resultlen = result->nwords;
 	for (i = 0; i < resultlen; i++)
-		result->words[i] &= other->words[i];
+	{
+		bitmapword	w = (result->words[i] &= other->words[i]);
+
+		/*
+		 * Compute bitwise OR of all bitmapwords to determine if the result
+		 * is empty
+		 */
+		bitwise_or |= w;
+	}
 	/* If we computed an empty result, we must return NULL */
-	if (bms_is_empty_internal(result))
+	if (bitwise_or == 0)
 	{
 		pfree(result);
 		return NULL;
@@ -711,30 +718,6 @@ bms_membership(const Bitmapset *a)
 	return result;
 }
 
-/*
- * bms_is_empty_internal - is a set empty?
- *
- * This is now used only locally, to detect cases where a function has
- * computed an empty set that we must now get rid of.  Hence, we can
- * assume the input isn't NULL.
- */
-static bool
-bms_is_empty_internal(const Bitmapset *a)
-{
-	int			nwords;
-	int			wordnum;
-
-	nwords = a->nwords;
-	for (wordnum = 0; wordnum < nwords; wordnum++)
-	{
-		bitmapword	w = a->words[wordnum];
-
-		if (w != 0)
-			return false;
-	}
-	return true;
-}
-
 
 /*
  * These operations all "recycle" their non-const inputs, ie, either
@@ -793,6 +776,7 @@ bms_del_member(Bitmapset *a, int x)
 {
 	int			wordnum,
 				bitnum;
+	bitmapword	bitwise_or = 0;
 
 	if (x < 0)
 		elog(ERROR, "negative bitmapset member not allowed");
@@ -801,9 +785,17 @@ bms_del_member(Bitmapset *a, int x)
 	wordnum = WORDNUM(x);
 	bitnum = BITNUM(x);
 	if (wordnum < a->nwords)
-		a->words[wordnum] &= ~((bitmapword) 1 << bitnum);
+	{
+		bitmapword	w = (a->words[wordnum] &= ~((bitmapword) 1 << bitnum));
+
+		/*
+		 * Compute bitwise OR of all bitmapwords to determine if the result
+		 * is empty
+		 */
+		bitwise_or |= w;
+	}
 	/* If we computed an empty result, we must return NULL */
-	if (bms_is_empty_internal(a))
+	if (bitwise_or == 0)
 	{
 		pfree(a);
 		return NULL;
@@ -929,6 +921,7 @@ bms_int_members(Bitmapset *a, const Bitmapset *b)
 {
 	int			shortlen;
 	int			i;
+	bitmapword	bitwise_or = 0;
 
 	/* Handle cases where either input is NULL */
 	if (a == NULL)
@@ -941,11 +934,19 @@ bms_int_members(Bitmapset *a, const Bitmapset *b)
 	/* Intersect b into a; we need never copy */
 	shortlen = Min(a->nwords, b->nwords);
 	for (i = 0; i < shortlen; i++)
-		a->words[i] &= b->words[i];
+	{
+		bitmapword	w = (a->words[i] &= b->words[i]);
+
+		/*
+		 * Compute bitwise OR of all bitmapwords to determine if the result
+		 * is empty
+		 */
+		bitwise_or |= w;
+	}
 	for (; i < a->nwords; i++)
 		a->words[i] = 0;
 	/* If we computed an empty result, we must return NULL */
-	if (bms_is_empty_internal(a))
+	if (bitwise_or == 0)
 	{
 		pfree(a);
 		return NULL;
@@ -961,6 +962,7 @@ bms_del_members(Bitmapset *a, const Bitmapset *b)
 {
 	int			shortlen;
 	int			i;
+	bitmapword	bitwise_or = 0;
 
 	/* Handle cases where either input is NULL */
 	if (a == NULL)
@@ -970,9 +972,17 @@ bms_del_members(Bitmapset *a, const Bitmapset *b)
 	/* Remove b's bits from a; we need never copy */
 	shortlen = Min(a->nwords, b->nwords);
 	for (i = 0; i < shortlen; i++)
-		a->words[i] &= ~b->words[i];
+	{
+		bitmapword	w = (a->words[i] &= ~b->words[i]);
+
+		/*
+		 * Compute bitwise OR of all bitmapwords to determine if the result
+		 * is empty
+		 */
+		bitwise_or |= w;
+	}
 	/* If we computed an empty result, we must return NULL */
-	if (bms_is_empty_internal(a))
+	if (bitwise_or == 0)
 	{
 		pfree(a);
 		return NULL;
-- 
2.39.2.windows.1

