From mboxrd@z Thu Jan 1 00:00:00 1970 From: Pavan Nikhilesh Subject: [PATCH v4] eal: add API to align integer to previous power of 2 Date: Wed, 4 Apr 2018 18:50:16 +0530 Message-ID: <20180404132016.13754-1-pbhagavatula@caviumnetworks.com> References: <20180217104934.17291-1-pbhagavatula@caviumnetworks.com> Mime-Version: 1.0 Content-Type: text/plain Cc: dev@dpdk.org, Pavan Nikhilesh To: jerin.jacob@caviumnetworks.com, matan@mellanox.com, keith.wiles@intel.com, thomas@monjalon.net Return-path: Received: from NAM03-DM3-obe.outbound.protection.outlook.com (mail-dm3nam03on0078.outbound.protection.outlook.com [104.47.41.78]) by dpdk.org (Postfix) with ESMTP id DA6E71C152 for ; Wed, 4 Apr 2018 15:20:38 +0200 (CEST) In-Reply-To: <20180217104934.17291-1-pbhagavatula@caviumnetworks.com> List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add 32b and 64b API's to align the given integer to the previous power of 2. Update common auto test to include test for previous power of 2 for both 32 and 64bit integers. Signed-off-by: Pavan Nikhilesh --- v4 Changes: - Squash patchset into a single patch. - Use %PRIu64 instead of %lu lib/librte_eal/common/include/rte_common.h | 92 ++++++++++++++++++++++++++---- test/test/test_common.c | 26 +++++++++ 2 files changed, 107 insertions(+), 11 deletions(-) diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h index c7803e41c..7e147dcf2 100644 --- a/lib/librte_eal/common/include/rte_common.h +++ b/lib/librte_eal/common/include/rte_common.h @@ -223,6 +223,51 @@ extern int RTE_BUILD_BUG_ON_detected_error; } while(0) #endif +/** + * Combines 32b inputs most significant set bits into the least + * significant bits to construct a value with the same MSBs as x + * but all 1's under it. + * + * @param x + * The integer whose MSBs need to be combined with its LSBs + * @return + * The combined value. + */ +static inline uint32_t +rte_combine32ms1b(register uint32_t x) +{ + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + + return x; +} + +/** + * Combines 64b inputs most significant set bits into the least + * significant bits to construct a value with the same MSBs as x + * but all 1's under it. + * + * @param v + * The integer whose MSBs need to be combined with its LSBs + * @return + * The combined value. + */ +static inline uint64_t +rte_combine64ms1b(register uint64_t v) +{ + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v |= v >> 32; + + return v; +} + /*********** Macros to work with powers of 2 ********/ /** @@ -250,15 +295,28 @@ static inline uint32_t rte_align32pow2(uint32_t x) { x--; - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; + x = rte_combine32ms1b(x); return x + 1; } +/** + * Aligns input parameter to the previous power of 2 + * + * @param x + * The integer value to algin + * + * @return + * Input parameter aligned to the previous power of 2 + */ +static inline uint32_t +rte_align32prevpow2(uint32_t x) +{ + x = rte_combine32ms1b(x); + + return x - (x >> 1); +} + /** * Aligns 64b input parameter to the next power of 2 * @@ -272,16 +330,28 @@ static inline uint64_t rte_align64pow2(uint64_t v) { v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v |= v >> 32; + v = rte_combine64ms1b(v); return v + 1; } +/** + * Aligns 64b input parameter to the previous power of 2 + * + * @param v + * The 64b value to align + * + * @return + * Input parameter aligned to the previous power of 2 + */ +static inline uint64_t +rte_align64prevpow2(uint64_t v) +{ + v = rte_combine64ms1b(v); + + return v - (v >> 1); +} + /*********** Macros for calculating min and max **********/ /** diff --git a/test/test/test_common.c b/test/test/test_common.c index d0342430f..7361693b8 100644 --- a/test/test/test_common.c +++ b/test/test/test_common.c @@ -3,6 +3,7 @@ */ #include +#include #include #include #include @@ -70,6 +71,9 @@ test_align(void) #define FAIL_ALIGN(x, i, p)\ {printf(x "() test failed: %u %u\n", i, p);\ return -1;} +#define FAIL_ALIGN64(x, j, q)\ + {printf(x "() test failed: %"PRIu64" %"PRIu64"\n", j, q);\ + return -1; } #define ERROR_FLOOR(res, i, pow) \ (res % pow) || /* check if not aligned */ \ ((res / pow) != (i / pow)) /* check if correct alignment */ @@ -80,6 +84,7 @@ test_align(void) val / pow != (i / pow) + 1) /* if not aligned, hence +1 */ uint32_t i, p, val; + uint64_t j, q; for (i = 1, p = 1; i <= MAX_NUM; i ++) { if (rte_align32pow2(i) != p) @@ -88,6 +93,27 @@ test_align(void) p <<= 1; } + for (i = 1, p = 1; i <= MAX_NUM; i++) { + if (rte_align32prevpow2(i) != p) + FAIL_ALIGN("rte_align32prevpow2", i, p); + if (rte_is_power_of_2(i + 1)) + p = i + 1; + } + + for (j = 1, q = 1; j <= MAX_NUM ; j++) { + if (rte_align64pow2(j) != q) + FAIL_ALIGN64("rte_align64pow2", j, q); + if (j == q) + q <<= 1; + } + + for (j = 1, q = 1; j <= MAX_NUM ; j++) { + if (rte_align64prevpow2(j) != q) + FAIL_ALIGN64("rte_align64prevpow2", j, q); + if (rte_is_power_of_2(j + 1)) + q = j + 1; + } + for (p = 2; p <= MAX_NUM; p <<= 1) { if (!rte_is_power_of_2(p)) -- 2.16.3