lib/find_bit: introduce FIND_FIRST_BIT() macro
authorYury Norov <yury.norov@gmail.com>
Thu, 15 Sep 2022 02:07:27 +0000 (19:07 -0700)
committerYury Norov <yury.norov@gmail.com>
Wed, 21 Sep 2022 19:15:53 +0000 (12:15 -0700)
Now that we have many flavors of find_first_bit(), and expect even more,
it's better to have one macro that generates optimal code for all and makes
maintaining of slightly different functions simpler.

The logic common to all versions is moved to the new macro, and all the
flavors are generated by providing an FETCH macro-parameter, like
in this example:

  #define FIND_FIRST_BIT(FETCH, MUNGE, size) ...

  find_first_ornot_and_bit(addr1, addr2, addr3, size)
  {
        return FIND_FIRST_BIT(addr1[idx] | ~addr2[idx] & addr3[idx], /* nop */, size);
  }

The FETCH may be of any complexity, as soon as it only refers
the bitmap(s) and an iterator idx.

MUNGE is here to support _le code generation for BE builds. May be
empty.

Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Reviewed-by: Valentin Schneider <vschneid@redhat.com>
Signed-off-by: Yury Norov <yury.norov@gmail.com>
lib/find_bit.c

index 1b8e4b2..894b656 100644 (file)
 #include <linux/minmax.h>
 #include <linux/swab.h>
 
+/*
+ * Common helper for find_bit() function family
+ * @FETCH: The expression that fetches and pre-processes each word of bitmap(s)
+ * @MUNGE: The expression that post-processes a word containing found bit (may be empty)
+ * @size: The bitmap size in bits
+ */
+#define FIND_FIRST_BIT(FETCH, MUNGE, size)                                     \
+({                                                                             \
+       unsigned long idx, val, sz = (size);                                    \
+                                                                               \
+       for (idx = 0; idx * BITS_PER_LONG < sz; idx++) {                        \
+               val = (FETCH);                                                  \
+               if (val) {                                                      \
+                       sz = min(idx * BITS_PER_LONG + __ffs(MUNGE(val)), sz);  \
+                       break;                                                  \
+               }                                                               \
+       }                                                                       \
+                                                                               \
+       sz;                                                                     \
+})
+
 #if !defined(find_next_bit) || !defined(find_next_zero_bit) ||                 \
        !defined(find_next_bit_le) || !defined(find_next_zero_bit_le) ||        \
        !defined(find_next_and_bit)
@@ -77,14 +98,7 @@ EXPORT_SYMBOL(_find_next_bit);
  */
 unsigned long _find_first_bit(const unsigned long *addr, unsigned long size)
 {
-       unsigned long idx;
-
-       for (idx = 0; idx * BITS_PER_LONG < size; idx++) {
-               if (addr[idx])
-                       return min(idx * BITS_PER_LONG + __ffs(addr[idx]), size);
-       }
-
-       return size;
+       return FIND_FIRST_BIT(addr[idx], /* nop */, size);
 }
 EXPORT_SYMBOL(_find_first_bit);
 #endif
@@ -97,15 +111,7 @@ unsigned long _find_first_and_bit(const unsigned long *addr1,
                                  const unsigned long *addr2,
                                  unsigned long size)
 {
-       unsigned long idx, val;
-
-       for (idx = 0; idx * BITS_PER_LONG < size; idx++) {
-               val = addr1[idx] & addr2[idx];
-               if (val)
-                       return min(idx * BITS_PER_LONG + __ffs(val), size);
-       }
-
-       return size;
+       return FIND_FIRST_BIT(addr1[idx] & addr2[idx], /* nop */, size);
 }
 EXPORT_SYMBOL(_find_first_and_bit);
 #endif
@@ -116,14 +122,7 @@ EXPORT_SYMBOL(_find_first_and_bit);
  */
 unsigned long _find_first_zero_bit(const unsigned long *addr, unsigned long size)
 {
-       unsigned long idx;
-
-       for (idx = 0; idx * BITS_PER_LONG < size; idx++) {
-               if (addr[idx] != ~0UL)
-                       return min(idx * BITS_PER_LONG + ffz(addr[idx]), size);
-       }
-
-       return size;
+       return FIND_FIRST_BIT(~addr[idx], /* nop */, size);
 }
 EXPORT_SYMBOL(_find_first_zero_bit);
 #endif