Skip to content
Permalink
Browse files
lib: add fast path for find_next_*_bit()
Like for bitmap functions, find_next_*_bit() users will benefit if
we'll handle a case of small-size bitmaps that fit into a single
word. In the best case, compiler will be able to replace a function
call with a single ffs or ffz instruction.
  • Loading branch information
YuryNorov committed Jan 19, 2021
1 parent 7ca7fca commit 850a7ee8fc507b8514365891d451a21d29f43f9f
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 0 deletions.
@@ -16,6 +16,18 @@ static __always_inline
unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
unsigned long offset)
{
if (small_const_nbits(size)) {
unsigned long val;

if (unlikely(offset >= size))
return size;

val = *addr & BITMAP_FIRST_WORD_MASK(offset)
& BITMAP_LAST_WORD_MASK(size);

return val ? __ffs(val) : size;
}

return _find_next_bit(addr, NULL, size, offset, 0UL, 0);
}
#endif
@@ -36,6 +48,18 @@ unsigned long find_next_and_bit(const unsigned long *addr1,
const unsigned long *addr2, unsigned long size,
unsigned long offset)
{
if (small_const_nbits(size)) {
unsigned long val;

if (unlikely(offset >= size))
return size;

val = *addr1 & *addr2 & BITMAP_FIRST_WORD_MASK(offset)
& BITMAP_LAST_WORD_MASK(size);

return val ? __ffs(val) : size;
}

return _find_next_bit(addr1, addr2, size, offset, 0UL, 0);
}
#endif
@@ -54,6 +78,18 @@ static __always_inline
unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
unsigned long offset)
{
if (small_const_nbits(size)) {
unsigned long val;

if (unlikely(offset >= size))
return size;

val = *addr | !BITMAP_FIRST_WORD_MASK(offset)
| !BITMAP_LAST_WORD_MASK(size);

return val == ~0UL ? size : ffz(val);
}

return _find_next_bit(addr, NULL, size, offset, ~0UL, 0);
}
#endif
@@ -36,6 +36,16 @@ static __always_inline
unsigned long find_next_zero_bit_le(const void *addr, unsigned
long size, unsigned long offset)
{
if (small_const_nbits(size)) {
unsigned long fz;

if (unlikely(offset >= size))
return size;

fz = ffz(swab(*addr & BITMAP_FIRST_WORD_MASK(offset)));
return fz < size ? fz : size;
}

return _find_next_bit(addr, NULL, size, offset, ~0UL, 1);
}
#endif
@@ -45,6 +55,16 @@ static __always_inline
unsigned long find_next_bit_le(const void *addr, unsigned
long size, unsigned long offset)
{
if (small_const_nbits(size)) {
unsigned long fs;

if (unlikely(offset >= size))
return size;

fs = __ffs(swab(*addr & BITMAP_FIRST_WORD_MASK(offset)));
return fs < size ? fs : size;
}

return _find_next_bit(addr, NULL, size, offset, 0UL, 1);
}
#endif

0 comments on commit 850a7ee

Please sign in to comment.