Skip to content

Commit

Permalink
bitops: find first set bit
Browse files Browse the repository at this point in the history
Provide toolchain abstraction for __builtin_ffs{,l,ll} gcc built-in
intrinsics.
Add associated unit tests.

Signed-off-by: Tyler Retzlaff <[email protected]>
Signed-off-by: Andre Muezerie <[email protected]>
  • Loading branch information
Tyler Retzlaff authored and david-marchand committed Jan 29, 2025
1 parent feb9fd6 commit 21cab84
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 0 deletions.
38 changes: 38 additions & 0 deletions app/test/test_bitcount.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,42 @@ test_popcount64(void)
return 0;
}

static int
test_bit_scan_forward(void)
{
unsigned int bit_nr;

TEST_ASSERT((bit_nr = rte_ffs32(0)) == 0,
"rte_ffs32 returned unexpected %d", bit_nr);

for (int i = 0; i < 32; ++i) {
uint32_t n = RTE_BIT32(i);

TEST_ASSERT((bit_nr = rte_ffs32(n)) == (unsigned int)(i+1),
"rte_ffs32 returned unexpected %d", bit_nr);
}

return TEST_SUCCESS;
}

static int
test_bit_scan_forward64(void)
{
unsigned int bit_nr;

TEST_ASSERT((bit_nr = rte_ffs64(0)) == 0,
"rte_ffs64 returned unexpected %d", bit_nr);

for (int i = 0; i < 64; ++i) {
uint64_t n = RTE_BIT64(i);

TEST_ASSERT((bit_nr = rte_ffs64(n)) == (unsigned int)(i+1),
"rte_ffs64 returned unexpected %d", bit_nr);
}

return TEST_SUCCESS;
}

static struct unit_test_suite bitcount_test_suite = {
.suite_name = "bitcount autotest",
.setup = NULL,
Expand All @@ -123,6 +159,8 @@ static struct unit_test_suite bitcount_test_suite = {
TEST_CASE(test_ctz64),
TEST_CASE(test_popcount32),
TEST_CASE(test_popcount64),
TEST_CASE(test_bit_scan_forward),
TEST_CASE(test_bit_scan_forward64),
TEST_CASES_END()
}
};
Expand Down
86 changes: 86 additions & 0 deletions lib/eal/include/rte_bitops.h
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,54 @@ rte_popcount64(uint64_t v)
return (unsigned int)__popcnt64(v);
}

/**
* @warning
* @b EXPERIMENTAL: this API may change without prior notice.
*
* Search v from least significant bit (LSB) to the most
* significant bit (MSB) for a set bit (1).
*
* @param v
* The value.
* @return
* Bit index + 1 if a set bit is found, zero otherwise.
*/
__rte_experimental
static inline unsigned int
rte_ffs32(uint32_t v)
{
unsigned long rv;

if (_BitScanForward(&rv, v) == 0)
return 0;

return (unsigned int)rv + 1;
}

/**
* @warning
* @b EXPERIMENTAL: this API may change without prior notice.
*
* Search v from least significant bit (LSB) to the most
* significant bit (MSB) for a set bit (1).
*
* @param v
* The value.
* @return
* Bit index + 1 if a set bit is found, zero otherwise.
*/
__rte_experimental
static inline unsigned int
rte_ffs64(uint64_t v)
{
unsigned long rv;

if (_BitScanForward64(&rv, v) == 0)
return 0;

return (unsigned int)rv + 1;
}

#else

/**
Expand Down Expand Up @@ -1044,6 +1092,44 @@ rte_popcount64(uint64_t v)
return (unsigned int)__builtin_popcountll(v);
}

/**
* @warning
* @b EXPERIMENTAL: this API may change without prior notice.
*
* Search v from least significant bit (LSB) to the most
* significant bit (MSB) for a set bit (1).
*
* @param v
* The value.
* @return
* Bit index + 1 if a set bit is found, zero otherwise.
*/
__rte_experimental
static inline unsigned int
rte_ffs32(uint32_t v)
{
return (unsigned int)__builtin_ffs(v);
}

/**
* @warning
* @b EXPERIMENTAL: this API may change without prior notice.
*
* Search v from least significant bit (LSB) to the most
* significant bit (MSB) for a set bit (1).
*
* @param v
* The value.
* @return
* Bit index + 1 if a set bit is found, zero otherwise.
*/
__rte_experimental
static inline unsigned int
rte_ffs64(uint64_t v)
{
return (unsigned int)__builtin_ffsll(v);
}

#endif

/**
Expand Down

0 comments on commit 21cab84

Please sign in to comment.