[v8,2/3] eal: provide abstracted bit count functions

Message ID 1680567118-6435-3-git-send-email-roretzla@linux.microsoft.com (mailing list archive)
State Accepted, archived
Delegated to: David Marchand
Headers
Series eal: provide abstracted bit counting functions |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Tyler Retzlaff April 4, 2023, 12:11 a.m. UTC
  Provide abstracted bit counting functions for count, leading and
trailing bits in v to hide compiler specific intrinsics and builtins.

Include basic unit test of following functions added.

    rte_clz32
    rte_clz64
    rte_ctz32
    rte_ctz64
    rte_popcount32
    rte_popcount64

Signed-off-by: Tyler Retzlaff <roretzla@linux.microsoft.com>
Acked-by: Morten Brørup <mb@smartsharesystems.com>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
---
 app/test/meson.build         |   2 +
 app/test/test_bitcount.c     | 136 ++++++++++++++++++++++++
 lib/eal/include/rte_bitops.h | 240 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 378 insertions(+)
 create mode 100644 app/test/test_bitcount.c
  

Patch

diff --git a/app/test/meson.build b/app/test/meson.build
index b9b5432..dafd509 100644
--- a/app/test/meson.build
+++ b/app/test/meson.build
@@ -13,6 +13,7 @@  test_sources = files(
         'test_alarm.c',
         'test_atomic.c',
         'test_barrier.c',
+        'test_bitcount.c',
         'test_bitops.c',
         'test_bitmap.c',
         'test_bpf.c',
@@ -161,6 +162,7 @@  test_deps += ['bus_pci', 'bus_vdev']
 fast_tests = [
         ['acl_autotest', true, true],
         ['atomic_autotest', false, true],
+        ['bitcount_autotest', true, true],
         ['bitmap_autotest', true, true],
         ['bpf_autotest', true, true],
         ['bpf_convert_autotest', true, true],
diff --git a/app/test/test_bitcount.c b/app/test/test_bitcount.c
new file mode 100644
index 0000000..5287ef7
--- /dev/null
+++ b/app/test/test_bitcount.c
@@ -0,0 +1,136 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C) 2022 Microsoft Corporation
+ */
+
+#include <limits.h>
+#include <string.h>
+
+#include <rte_bitops.h>
+#include <rte_debug.h>
+
+#include "test.h"
+
+RTE_LOG_REGISTER(bitcount_logtype_test, test.bitcount, INFO);
+
+static int
+test_clz32(void)
+{
+	size_t leading;
+	uint32_t v = 0xffffffff;
+
+	for (leading = 0; v; leading++) {
+		RTE_TEST_ASSERT(rte_clz32(v) == leading,
+		    "Unexpected count.");
+		v >>= 1;
+	}
+
+	return 0;
+}
+
+static int
+test_clz64(void)
+{
+	size_t leading;
+	uint64_t v = 0xffffffffffffffff;
+
+	for (leading = 0; v; leading++) {
+		RTE_TEST_ASSERT(rte_clz64(v) == leading,
+		    "Unexpected count.");
+		v >>= 1;
+	}
+
+	return 0;
+}
+
+static int
+test_ctz32(void)
+{
+	size_t trailing;
+	uint32_t v = 1;
+
+	for (trailing = 0; v; trailing++) {
+		RTE_TEST_ASSERT(rte_ctz32(v) == trailing,
+		    "Unexpected count.");
+		v <<= 1;
+	}
+
+	return 0;
+}
+
+static int
+test_ctz64(void)
+{
+	size_t trailing;
+	uint64_t v = 1;
+
+	for (trailing = 0; v; trailing++) {
+		RTE_TEST_ASSERT(rte_ctz64(v) == trailing,
+		    "Unexpected count.");
+		v <<= 1;
+	}
+
+	return 0;
+}
+
+static int
+test_popcount32(void)
+{
+	size_t shift;
+	uint32_t v = 0;
+	const size_t bits = sizeof(v) * CHAR_BIT;
+
+	for (shift = 0; shift < bits; shift++) {
+		RTE_TEST_ASSERT(rte_popcount32(v) == shift,
+		    "Unexpected count.");
+		v <<= 1;
+		v |= 1;
+	}
+
+	RTE_TEST_ASSERT(rte_popcount32(v) == bits,
+	    "Unexpected count.");
+
+	return 0;
+}
+
+static int
+test_popcount64(void)
+{
+	size_t shift;
+	uint64_t v = 0;
+	const size_t bits = sizeof(v) * CHAR_BIT;
+
+	for (shift = 0; shift < bits; shift++) {
+		RTE_TEST_ASSERT(rte_popcount64(v) == shift,
+		    "Unexpected count.");
+		v <<= 1;
+		v |= 1;
+	}
+
+	RTE_TEST_ASSERT(rte_popcount64(v) == bits,
+	    "Unexpected count.");
+
+	return 0;
+}
+
+static struct unit_test_suite bitcount_test_suite = {
+	.suite_name = "bitcount autotest",
+	.setup = NULL,
+	.teardown = NULL,
+	.unit_test_cases = {
+		TEST_CASE(test_clz32),
+		TEST_CASE(test_clz64),
+		TEST_CASE(test_ctz32),
+		TEST_CASE(test_ctz64),
+		TEST_CASE(test_popcount32),
+		TEST_CASE(test_popcount64),
+		TEST_CASES_END()
+	}
+};
+
+static int
+test_bitcount(void)
+{
+	return unit_test_suite_runner(&bitcount_test_suite);
+}
+
+REGISTER_TEST_COMMAND(bitcount_autotest, test_bitcount);
diff --git a/lib/eal/include/rte_bitops.h b/lib/eal/include/rte_bitops.h
index 531479e..d45aa54 100644
--- a/lib/eal/include/rte_bitops.h
+++ b/lib/eal/include/rte_bitops.h
@@ -1,5 +1,7 @@ 
 /* SPDX-License-Identifier: BSD-3-Clause
  * Copyright(c) 2020 Arm Limited
+ * Copyright(c) 2010-2019 Intel Corporation
+ * Copyright(c) 2023 Microsoft Corporation
  */
 
 #ifndef _RTE_BITOPS_H_
@@ -275,6 +277,244 @@ 
 	return val & mask;
 }
 
+#ifdef RTE_TOOLCHAIN_MSVC
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Get the count of leading 0-bits in v.
+ *
+ * @param v
+ *   The value.
+ * @return
+ *   The count of leading zero bits.
+ */
+__rte_experimental
+static inline unsigned int
+rte_clz32(uint32_t v)
+{
+	unsigned long rv;
+
+	(void)_BitScanReverse(&rv, v);
+
+	return (unsigned int)(sizeof(v) * CHAR_BIT - 1 - rv);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Get the count of leading 0-bits in v.
+ *
+ * @param v
+ *   The value.
+ * @return
+ *   The count of leading zero bits.
+ */
+__rte_experimental
+static inline unsigned int
+rte_clz64(uint64_t v)
+{
+	unsigned long rv;
+
+	(void)_BitScanReverse64(&rv, v);
+
+	return (unsigned int)(sizeof(v) * CHAR_BIT - 1 - rv);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Get the count of trailing 0-bits in v.
+ *
+ * @param v
+ *   The value.
+ * @return
+ *   The count of trailing zero bits.
+ */
+__rte_experimental
+static inline unsigned int
+rte_ctz32(uint32_t v)
+{
+	unsigned long rv;
+
+	(void)_BitScanForward(&rv, v);
+
+	return (unsigned int)rv;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Get the count of trailing 0-bits in v.
+ *
+ * @param v
+ *   The value.
+ * @return
+ *   The count of trailing zero bits.
+ */
+__rte_experimental
+static inline unsigned int
+rte_ctz64(uint64_t v)
+{
+	unsigned long rv;
+
+	(void)_BitScanForward64(&rv, v);
+
+	return (unsigned int)rv;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Get the count of 1-bits in v.
+ *
+ * @param v
+ *   The value.
+ * @return
+ *   The count of 1-bits.
+ */
+__rte_experimental
+static inline unsigned int
+rte_popcount32(uint32_t v)
+{
+	return (unsigned int)__popcnt(v);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Get the count of 1-bits in v.
+ *
+ * @param v
+ *   The value.
+ * @return
+ *   The count of 1-bits.
+ */
+__rte_experimental
+static inline unsigned int
+rte_popcount64(uint64_t v)
+{
+	return (unsigned int)__popcnt64(v);
+}
+
+#else
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Get the count of leading 0-bits in v.
+ *
+ * @param v
+ *   The value.
+ * @return
+ *   The count of leading zero bits.
+ */
+__rte_experimental
+static inline unsigned int
+rte_clz32(uint32_t v)
+{
+	return (unsigned int)__builtin_clz(v);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Get the count of leading 0-bits in v.
+ *
+ * @param v
+ *   The value.
+ * @return
+ *   The count of leading zero bits.
+ */
+__rte_experimental
+static inline unsigned int
+rte_clz64(uint64_t v)
+{
+	return (unsigned int)__builtin_clzll(v);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Get the count of trailing 0-bits in v.
+ *
+ * @param v
+ *   The value.
+ * @return
+ *   The count of trailing zero bits.
+ */
+__rte_experimental
+static inline unsigned int
+rte_ctz32(uint32_t v)
+{
+	return (unsigned int)__builtin_ctz(v);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Get the count of trailing 0-bits in v.
+ *
+ * @param v
+ *   The value.
+ * @return
+ *   The count of trailing zero bits.
+ */
+__rte_experimental
+static inline unsigned int
+rte_ctz64(uint64_t v)
+{
+	return (unsigned int)__builtin_ctzll(v);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Get the count of 1-bits in v.
+ *
+ * @param v
+ *   The value.
+ * @return
+ *   The count of 1-bits.
+ */
+__rte_experimental
+static inline unsigned int
+rte_popcount32(uint32_t v)
+{
+	return (unsigned int)__builtin_popcount(v);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Get the count of 1-bits in v.
+ *
+ * @param v
+ *   The value.
+ * @return
+ *   The count of 1-bits.
+ */
+__rte_experimental
+static inline unsigned int
+rte_popcount64(uint64_t v)
+{
+	return (unsigned int)__builtin_popcountll(v);
+}
+
+#endif
+
 /**
  * Combines 32b inputs most significant set bits into the least
  * significant bits to construct a value with the same MSBs as x