From 365b42a48e860d7926d72280f144544704cf51a2 Mon Sep 17 00:00:00 2001 From: Pavel P Date: Thu, 27 Mar 2025 02:45:39 +0200 Subject: [PATCH 1/7] : Improve std::has_single_bit --- stl/inc/bit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/bit b/stl/inc/bit index 9a73c616375..6d82d9bc106 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -84,7 +84,7 @@ _NODISCARD constexpr int countl_zero(_Ty _Val) noexcept; _EXPORT_STD template <_Standard_unsigned_integral _Ty> _NODISCARD constexpr bool has_single_bit(const _Ty _Val) noexcept { - return _Val != 0 && (_Val & (_Val - 1)) == 0; + return (_Val ^ (_Val - 1)) > _Val - 1; } inline void _Precondition_violation_in_bit_ceil() noexcept {} From 59a62b871d806320f10e6461f589411168271fd0 Mon Sep 17 00:00:00 2001 From: Pavel P Date: Thu, 27 Mar 2025 14:12:52 +0200 Subject: [PATCH 2/7] Keep old code for 32-bit x86 (30% faster) --- stl/inc/bit | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/stl/inc/bit b/stl/inc/bit index 6d82d9bc106..eb35d0f25b2 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -84,7 +84,11 @@ _NODISCARD constexpr int countl_zero(_Ty _Val) noexcept; _EXPORT_STD template <_Standard_unsigned_integral _Ty> _NODISCARD constexpr bool has_single_bit(const _Ty _Val) noexcept { +#ifndef _M_IX86 return (_Val ^ (_Val - 1)) > _Val - 1; +#else + return _Val != 0 && (_Val & (_Val - 1)) == 0; +#endif } inline void _Precondition_violation_in_bit_ceil() noexcept {} From b96db7ad6f8961e8649b03777824855ff90d2ed1 Mon Sep 17 00:00:00 2001 From: Pavel P Date: Thu, 27 Mar 2025 15:55:58 +0200 Subject: [PATCH 3/7] Add has_single_bit benchmark --- benchmarks/CMakeLists.txt | 1 + benchmarks/src/has_single_bit.cpp | 51 +++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 benchmarks/src/has_single_bit.cpp diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index b551efa42cc..046f8cd8675 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -114,6 +114,7 @@ add_benchmark(efficient_nonlocking_print src/efficient_nonlocking_print.cpp) add_benchmark(filesystem src/filesystem.cpp) add_benchmark(find_and_count src/find_and_count.cpp) add_benchmark(find_first_of src/find_first_of.cpp) +add_benchmark(has_single_bit src/has_single_bit.cpp) add_benchmark(iota src/iota.cpp) add_benchmark(locale_classic src/locale_classic.cpp) add_benchmark(minmax_element src/minmax_element.cpp) diff --git a/benchmarks/src/has_single_bit.cpp b/benchmarks/src/has_single_bit.cpp new file mode 100644 index 00000000000..adb9975e28d --- /dev/null +++ b/benchmarks/src/has_single_bit.cpp @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include + +#include + +template +static void has_single_bit_if(benchmark::State& state) { + const auto random_v = random_vector(8); + for (auto _ : state) { + benchmark::DoNotOptimize(random_v); + int count_true = 0, count_false = 0; + for (const auto& x : random_v) { + if (std::has_single_bit(x)) { + benchmark::DoNotOptimize(count_true++); + } else { + benchmark::DoNotOptimize(count_false++); + } + } + } +} + +template +static void has_single_bit(benchmark::State& state) { + const auto random_v = random_vector(8); + assert(random_v.size() % 4 == 0); + for (auto _ : state) { + benchmark::DoNotOptimize(random_v); + int r = 0; + for (size_t i = 0; i < random_v.size(); i += 4) { + r += std::has_single_bit(random_v[i + 0]); + r += std::has_single_bit(random_v[i + 1]); + r += std::has_single_bit(random_v[i + 2]); + r += std::has_single_bit(random_v[i + 3]); + } + benchmark::DoNotOptimize(r); + } +} + +BENCHMARK(has_single_bit_if); +BENCHMARK(has_single_bit_if); +BENCHMARK(has_single_bit_if); + +BENCHMARK(has_single_bit); +BENCHMARK(has_single_bit); +BENCHMARK(has_single_bit); + +BENCHMARK_MAIN(); From f546b3b1c9fc5cbdd4bccd6e95fc9c4cf52b6bdb Mon Sep 17 00:00:00 2001 From: Pavel P Date: Thu, 27 Mar 2025 17:33:44 +0200 Subject: [PATCH 4/7] update --- benchmarks/src/has_single_bit.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/benchmarks/src/has_single_bit.cpp b/benchmarks/src/has_single_bit.cpp index adb9975e28d..013f87b44b4 100644 --- a/benchmarks/src/has_single_bit.cpp +++ b/benchmarks/src/has_single_bit.cpp @@ -8,11 +8,12 @@ #include template -static void has_single_bit_if(benchmark::State& state) { +void has_single_bit_if(benchmark::State& state) { const auto random_v = random_vector(8); for (auto _ : state) { benchmark::DoNotOptimize(random_v); - int count_true = 0, count_false = 0; + unsigned count_true = 0; + unsigned count_false = 0; for (const auto& x : random_v) { if (std::has_single_bit(x)) { benchmark::DoNotOptimize(count_true++); @@ -24,12 +25,12 @@ static void has_single_bit_if(benchmark::State& state) { } template -static void has_single_bit(benchmark::State& state) { +void has_single_bit(benchmark::State& state) { const auto random_v = random_vector(8); assert(random_v.size() % 4 == 0); for (auto _ : state) { benchmark::DoNotOptimize(random_v); - int r = 0; + unsigned r = 0; for (size_t i = 0; i < random_v.size(); i += 4) { r += std::has_single_bit(random_v[i + 0]); r += std::has_single_bit(random_v[i + 1]); From 14656fce96a18d07635413422569d4711e62ac7e Mon Sep 17 00:00:00 2001 From: Pavel P Date: Thu, 27 Mar 2025 17:49:16 +0200 Subject: [PATCH 5/7] test 1 per iteration --- benchmarks/src/has_single_bit.cpp | 7 ++----- stl/inc/bit | 4 ---- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/benchmarks/src/has_single_bit.cpp b/benchmarks/src/has_single_bit.cpp index 013f87b44b4..28b97178268 100644 --- a/benchmarks/src/has_single_bit.cpp +++ b/benchmarks/src/has_single_bit.cpp @@ -31,11 +31,8 @@ void has_single_bit(benchmark::State& state) { for (auto _ : state) { benchmark::DoNotOptimize(random_v); unsigned r = 0; - for (size_t i = 0; i < random_v.size(); i += 4) { - r += std::has_single_bit(random_v[i + 0]); - r += std::has_single_bit(random_v[i + 1]); - r += std::has_single_bit(random_v[i + 2]); - r += std::has_single_bit(random_v[i + 3]); + for (const auto& x : random_v) { + r += std::has_single_bit(x); } benchmark::DoNotOptimize(r); } diff --git a/stl/inc/bit b/stl/inc/bit index eb35d0f25b2..6d82d9bc106 100644 --- a/stl/inc/bit +++ b/stl/inc/bit @@ -84,11 +84,7 @@ _NODISCARD constexpr int countl_zero(_Ty _Val) noexcept; _EXPORT_STD template <_Standard_unsigned_integral _Ty> _NODISCARD constexpr bool has_single_bit(const _Ty _Val) noexcept { -#ifndef _M_IX86 return (_Val ^ (_Val - 1)) > _Val - 1; -#else - return _Val != 0 && (_Val & (_Val - 1)) == 0; -#endif } inline void _Precondition_violation_in_bit_ceil() noexcept {} From 283c320c42fdd0d34cc58f21aa777fcf51abf32c Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 1 Apr 2025 11:03:59 -0700 Subject: [PATCH 6/7] Code review feedback. --- benchmarks/src/has_single_bit.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/benchmarks/src/has_single_bit.cpp b/benchmarks/src/has_single_bit.cpp index 28b97178268..4d2c130f03d 100644 --- a/benchmarks/src/has_single_bit.cpp +++ b/benchmarks/src/has_single_bit.cpp @@ -1,24 +1,26 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#include #include #include +#include #include +using namespace std; + template void has_single_bit_if(benchmark::State& state) { const auto random_v = random_vector(8); for (auto _ : state) { benchmark::DoNotOptimize(random_v); - unsigned count_true = 0; - unsigned count_false = 0; + unsigned int count_true = 0; + unsigned int count_false = 0; for (const auto& x : random_v) { - if (std::has_single_bit(x)) { - benchmark::DoNotOptimize(count_true++); + if (has_single_bit(x)) { + benchmark::DoNotOptimize(++count_true); } else { - benchmark::DoNotOptimize(count_false++); + benchmark::DoNotOptimize(++count_false); } } } @@ -27,21 +29,22 @@ void has_single_bit_if(benchmark::State& state) { template void has_single_bit(benchmark::State& state) { const auto random_v = random_vector(8); - assert(random_v.size() % 4 == 0); for (auto _ : state) { benchmark::DoNotOptimize(random_v); - unsigned r = 0; + unsigned int r = 0; for (const auto& x : random_v) { - r += std::has_single_bit(x); + r += has_single_bit(x); } benchmark::DoNotOptimize(r); } } +BENCHMARK(has_single_bit_if); BENCHMARK(has_single_bit_if); BENCHMARK(has_single_bit_if); BENCHMARK(has_single_bit_if); +BENCHMARK(has_single_bit); BENCHMARK(has_single_bit); BENCHMARK(has_single_bit); BENCHMARK(has_single_bit); From eddb362cba8c7f95e62f9d627f106be00bdc6add Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 9 Apr 2025 05:18:06 -0700 Subject: [PATCH 7/7] Avoid shadowing. --- benchmarks/src/has_single_bit.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/benchmarks/src/has_single_bit.cpp b/benchmarks/src/has_single_bit.cpp index 4d2c130f03d..7f2519e0a1c 100644 --- a/benchmarks/src/has_single_bit.cpp +++ b/benchmarks/src/has_single_bit.cpp @@ -10,7 +10,7 @@ using namespace std; template -void has_single_bit_if(benchmark::State& state) { +void bm_has_single_bit_if(benchmark::State& state) { const auto random_v = random_vector(8); for (auto _ : state) { benchmark::DoNotOptimize(random_v); @@ -27,7 +27,7 @@ void has_single_bit_if(benchmark::State& state) { } template -void has_single_bit(benchmark::State& state) { +void bm_has_single_bit(benchmark::State& state) { const auto random_v = random_vector(8); for (auto _ : state) { benchmark::DoNotOptimize(random_v); @@ -39,14 +39,14 @@ void has_single_bit(benchmark::State& state) { } } -BENCHMARK(has_single_bit_if); -BENCHMARK(has_single_bit_if); -BENCHMARK(has_single_bit_if); -BENCHMARK(has_single_bit_if); +BENCHMARK(bm_has_single_bit_if); +BENCHMARK(bm_has_single_bit_if); +BENCHMARK(bm_has_single_bit_if); +BENCHMARK(bm_has_single_bit_if); -BENCHMARK(has_single_bit); -BENCHMARK(has_single_bit); -BENCHMARK(has_single_bit); -BENCHMARK(has_single_bit); +BENCHMARK(bm_has_single_bit); +BENCHMARK(bm_has_single_bit); +BENCHMARK(bm_has_single_bit); +BENCHMARK(bm_has_single_bit); BENCHMARK_MAIN();