From 3ebbaf08fb9236023b8f37bb9e9de85a9be8e281 Mon Sep 17 00:00:00 2001 From: Ryan Macnak Date: Mon, 5 Jan 2026 15:14:59 -0800 Subject: [PATCH] [vm] Use C++20 bit manipulation implementations. TEST=ci Change-Id: I0aee472e2074ff4f03f05df573aff7616418c72c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/468904 Reviewed-by: Alexander Aprelev Commit-Queue: Ryan Macnak --- runtime/platform/utils.h | 132 ++++------------------------------ runtime/vm/simulator_riscv.cc | 69 +++--------------- 2 files changed, 26 insertions(+), 175 deletions(-) diff --git a/runtime/platform/utils.h b/runtime/platform/utils.h index 2eed8295506..2d283badac3 100644 --- a/runtime/platform/utils.h +++ b/runtime/platform/utils.h @@ -5,6 +5,7 @@ #ifndef RUNTIME_PLATFORM_UTILS_H_ #define RUNTIME_PLATFORM_UTILS_H_ +#include #include #include #include @@ -74,7 +75,8 @@ class Utils { template static constexpr bool IsPowerOfTwo(T x) { - return ((x & (x - 1)) == 0) && (x != 0); + using Unsigned = typename std::make_unsigned::type; + return std::has_single_bit(static_cast(x)); } template @@ -130,56 +132,14 @@ class Utils { RoundUp(reinterpret_cast(x), alignment, offset)); } - // Implementation is from "Hacker's Delight" by Henry S. Warren, Jr., - // figure 3-3, page 48, where the function is called clp2. static constexpr uintptr_t RoundUpToPowerOfTwo(uintptr_t x) { - x = x - 1; - x = x | (x >> 1); - x = x | (x >> 2); - x = x | (x >> 4); - x = x | (x >> 8); - x = x | (x >> 16); -#if defined(ARCH_IS_64_BIT) - x = x | (x >> 32); -#endif // defined(ARCH_IS_64_BIT) - return x + 1; + if (x == 0) return 0; + return std::bit_ceil(x); } - static constexpr int CountOneBits64(uint64_t x) { - // Apparently there are x64 chips without popcount. -#if __GNUC__ && !defined(HOST_ARCH_IA32) && !defined(HOST_ARCH_X64) - return __builtin_popcountll(x); -#else - x = x - ((x >> 1) & 0x5555555555555555); - x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333); - x = (((x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f) * 0x0101010101010101) >> 56; - return x; -#endif - } - - static constexpr int CountOneBits32(uint32_t x) { - // Apparently there are x64 chips without popcount. -#if __GNUC__ && !defined(HOST_ARCH_IA32) && !defined(HOST_ARCH_X64) - return __builtin_popcount(x); -#else - // Implementation is from "Hacker's Delight" by Henry S. Warren, Jr., - // figure 5-2, page 66, where the function is called pop. - x = x - ((x >> 1) & 0x55555555); - x = (x & 0x33333333) + ((x >> 2) & 0x33333333); - x = (x + (x >> 4)) & 0x0F0F0F0F; - x = x + (x >> 8); - x = x + (x >> 16); - return static_cast(x & 0x0000003F); -#endif - } - - static constexpr int CountOneBitsWord(uword x) { -#ifdef ARCH_IS_64_BIT - return CountOneBits64(x); -#else - return CountOneBits32(x); -#endif - } + static constexpr int CountOneBits64(uint64_t x) { return std::popcount(x); } + static constexpr int CountOneBits32(uint32_t x) { return std::popcount(x); } + static constexpr int CountOneBitsWord(uword x) { return std::popcount(x); } // TODO(koda): Compare to flsll call/intrinsic. static constexpr size_t HighestBit(int64_t v) { @@ -213,78 +173,16 @@ class Utils { static constexpr size_t BitLength(int64_t value) { // Flip bits if negative (-1 becomes 0). value ^= value >> (8 * sizeof(value) - 1); - return (value == 0) ? 0 : (Utils::HighestBit(value) + 1); + return std::bit_width(static_cast(value)); } - static int CountLeadingZeros32(uint32_t x) { -#if defined(DART_HOST_OS_WINDOWS) - unsigned long position; // NOLINT - return (_BitScanReverse(&position, x) == 0) - ? 32 - : 31 - static_cast(position); -#else - return x == 0 ? 32 : __builtin_clz(x); -#endif - } - static int CountLeadingZeros64(uint64_t x) { -#if defined(DART_HOST_OS_WINDOWS) -#if defined(ARCH_IS_32_BIT) - const uint32_t x_hi = static_cast(x >> 32); - if (x_hi != 0) { - return CountLeadingZeros32(x_hi); - } - return 32 + CountLeadingZeros32(static_cast(x)); -#else - unsigned long position; // NOLINT - return (_BitScanReverse64(&position, x) == 0) - ? 64 - : 63 - static_cast(position); -#endif -#else - return x == 0 ? 64 : __builtin_clzll(x); -#endif - } - static int CountLeadingZerosWord(uword x) { -#ifdef ARCH_IS_64_BIT - return CountLeadingZeros64(x); -#else - return CountLeadingZeros32(x); -#endif - } + static int CountLeadingZeros32(uint32_t x) { return std::countl_zero(x); } + static int CountLeadingZeros64(uint64_t x) { return std::countl_zero(x); } + static int CountLeadingZerosWord(uword x) { return std::countl_zero(x); } - static int CountTrailingZeros32(uint32_t x) { -#if defined(DART_HOST_OS_WINDOWS) - unsigned long position; // NOLINT - return (_BitScanForward(&position, x) == 0) ? 32 - : static_cast(position); -#else - return x == 0 ? 32 : __builtin_ctz(x); -#endif - } - static int CountTrailingZeros64(uint64_t x) { -#if defined(DART_HOST_OS_WINDOWS) -#if defined(ARCH_IS_32_BIT) - const uint32_t x_lo = static_cast(x); - if (x_lo != 0) { - return CountTrailingZeros32(x_lo); - } - return 32 + CountTrailingZeros32(static_cast(x >> 32)); -#else - unsigned long position; // NOLINT - return (_BitScanForward64(&position, x) == 0) ? 64 - : static_cast(position); -#endif -#else - return x == 0 ? 64 : __builtin_ctzll(x); -#endif - } - static int CountTrailingZerosWord(uword x) { -#ifdef ARCH_IS_64_BIT - return CountTrailingZeros64(x); -#else - return CountTrailingZeros32(x); -#endif - } + static int CountTrailingZeros32(uint32_t x) { return std::countr_zero(x); } + static int CountTrailingZeros64(uint64_t x) { return std::countr_zero(x); } + static int CountTrailingZerosWord(uword x) { return std::countr_zero(x); } static uint64_t ReverseBits64(uint64_t x); static uint32_t ReverseBits32(uint32_t x); diff --git a/runtime/vm/simulator_riscv.cc b/runtime/vm/simulator_riscv.cc index dafb051fe10..0a42bd481b2 100644 --- a/runtime/vm/simulator_riscv.cc +++ b/runtime/vm/simulator_riscv.cc @@ -5,6 +5,7 @@ #include // NOLINT #include +#include #include #include "vm/globals.h" @@ -818,61 +819,23 @@ static uint32_t remuw(uint32_t a, uint32_t b) { #endif // XLEN >= 64 static uintx_t clz(uintx_t a) { - for (int bit = XLEN - 1; bit >= 0; bit--) { - if ((a & (static_cast(1) << bit)) != 0) { - return XLEN - bit - 1; - } - } - return XLEN; + return std::countl_zero(a); } - static uintx_t ctz(uintx_t a) { - for (int bit = 0; bit < XLEN; bit++) { - if ((a & (static_cast(1) << bit)) != 0) { - return bit; - } - } - return XLEN; + return std::countr_zero(a); } - static uintx_t cpop(uintx_t a) { - uintx_t count = 0; - for (int bit = 0; bit < XLEN; bit++) { - if ((a & (static_cast(1) << bit)) != 0) { - count++; - } - } - return count; + return std::popcount(a); } - static uintx_t clzw(uint32_t a) { - for (int bit = 32 - 1; bit >= 0; bit--) { - if ((a & (static_cast(1) << bit)) != 0) { - return 32 - bit - 1; - } - } - return 32; + return std::countl_zero(a); } - static uintx_t ctzw(uint32_t a) { - for (int bit = 0; bit < 32; bit++) { - if ((a & (static_cast(1) << bit)) != 0) { - return bit; - } - } - return 32; + return std::countr_zero(a); } - static uintx_t cpopw(uint32_t a) { - uintx_t count = 0; - for (int bit = 0; bit < 32; bit++) { - if ((a & (static_cast(1) << bit)) != 0) { - count++; - } - } - return count; + return std::popcount(a); } - static intx_t max(intx_t a, intx_t b) { return a > b ? a : b; } @@ -930,26 +893,16 @@ static uintx_t zextw(uintx_t a) { } #endif static uintx_t ror(uintx_t a, uintx_t b) { - uintx_t r = b & (XLEN - 1); - uintx_t l = (XLEN - r) & (XLEN - 1); - return (a << l) | (a >> r); + return std::rotr(a, b & (XLEN - 1)); } static uintx_t rol(uintx_t a, uintx_t b) { - uintx_t l = b & (XLEN - 1); - uintx_t r = (XLEN - l) & (XLEN - 1); - return (a << l) | (a >> r); + return std::rotl(a, b & (XLEN - 1)); } static uintx_t rorw(uintx_t a, uintx_t b) { - uint32_t r = b & (XLEN - 1); - uint32_t l = (XLEN - r) & (XLEN - 1); - uint32_t x = a; - return sign_extend((x << l) | (x >> r)); + return sign_extend(std::rotr(static_cast(a), b & (XLEN - 1))); } static uintx_t rolw(uintx_t a, uintx_t b) { - uint32_t l = b & (XLEN - 1); - uint32_t r = (XLEN - l) & (XLEN - 1); - uint32_t x = a; - return sign_extend((x << l) | (x >> r)); + return sign_extend(std::rotl(static_cast(a), b & (XLEN - 1))); } static uintx_t orcb(uintx_t a) { uintx_t result = 0;