From e8b62e8d72d24171157a230a67d124d150443429 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 2 May 2024 09:57:38 +0300 Subject: [PATCH 1/4] Help the compiler vectorize `ranges::iota` Ranges version of #4627 --- benchmarks/src/iota.cpp | 2 +- stl/inc/numeric | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/benchmarks/src/iota.cpp b/benchmarks/src/iota.cpp index 9d96d12d773..d6fcab9a369 100644 --- a/benchmarks/src/iota.cpp +++ b/benchmarks/src/iota.cpp @@ -14,7 +14,7 @@ void bm(benchmark::State& state) { std::vector a(size); for (auto _ : state) { - std::iota(a.begin(), a.end(), T{22}); + std::ranges::iota(a, T{22}); benchmark::DoNotOptimize(a); } } diff --git a/stl/inc/numeric b/stl/inc/numeric index a0186094e52..31085f86ee5 100644 --- a/stl/inc/numeric +++ b/stl/inc/numeric @@ -567,6 +567,22 @@ namespace ranges { _STL_INTERNAL_STATIC_ASSERT(weakly_incrementable<_Ty>); _STL_INTERNAL_STATIC_ASSERT(indirectly_writable<_It, const _Ty&>); + if constexpr (_Iterator_is_contiguous<_It> && sized_sentinel_for<_Se, _It> && is_integral_v<_Ty> + && sizeof(_Ty) >= 4) { + // TRANSITION, DevCom-10593477: help the compiler vectorize + const auto _Ptr = _To_address(_First); + const auto _Size = static_cast(_Last - _First); + + if (_STD _In_range<_Ty>(_Size)) { + const auto _Size_typed = static_cast<_Ty>(_Size); + for (_Ty _Ix = 0; _Ix != _Size_typed; ++_Ix) { + _Ptr[_Ix] = _Val + _Ix; + } + + return _First + _Size; + } + } + const _Ty& _Const_val = _Val; for (; _First != _Last; ++_First, (void) ++_Val) { *_First = _Const_val; From cedc297372dddb8907244ff396016981f657e3b3 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 2 May 2024 11:50:06 +0300 Subject: [PATCH 2/4] missing `const` --- stl/inc/numeric | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stl/inc/numeric b/stl/inc/numeric index 31085f86ee5..dfa240e82eb 100644 --- a/stl/inc/numeric +++ b/stl/inc/numeric @@ -576,7 +576,8 @@ namespace ranges { if (_STD _In_range<_Ty>(_Size)) { const auto _Size_typed = static_cast<_Ty>(_Size); for (_Ty _Ix = 0; _Ix != _Size_typed; ++_Ix) { - _Ptr[_Ix] = _Val + _Ix; + const _Ty _Const_val = _Val + _Ix; + _Ptr[_Ix] = _Const_val; } return _First + _Size; From c87c40358a2f870ed06fdc3650a1662dd2c322c6 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 2 May 2024 19:16:09 +0300 Subject: [PATCH 3/4] Aha! --- stl/inc/numeric | 1 + 1 file changed, 1 insertion(+) diff --git a/stl/inc/numeric b/stl/inc/numeric index dfa240e82eb..9f4af6eb911 100644 --- a/stl/inc/numeric +++ b/stl/inc/numeric @@ -580,6 +580,7 @@ namespace ranges { _Ptr[_Ix] = _Const_val; } + _Val += _Size_typed; return _First + _Size; } } From 8d4e563285b2de571379eeb3b79acc087d94944e Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 15 May 2024 18:59:22 -0700 Subject: [PATCH 4/4] Benchmark both algorithms. --- benchmarks/src/iota.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/benchmarks/src/iota.cpp b/benchmarks/src/iota.cpp index d6fcab9a369..5860b1b605e 100644 --- a/benchmarks/src/iota.cpp +++ b/benchmarks/src/iota.cpp @@ -7,14 +7,24 @@ #include #include -template +enum class Alg { + Std, + Rng, +}; + +template void bm(benchmark::State& state) { const auto size = static_cast(state.range(0)); std::vector a(size); for (auto _ : state) { - std::ranges::iota(a, T{22}); + if constexpr (Algorithm == Alg::Std) { + std::iota(a.begin(), a.end(), T{22}); + } else if constexpr (Algorithm == Alg::Rng) { + std::ranges::iota(a, T{22}); + } + benchmark::DoNotOptimize(a); } } @@ -23,7 +33,10 @@ void common_args(auto bm) { bm->Arg(7)->Arg(18)->Arg(43)->Arg(131)->Arg(315)->Arg(1212); } -BENCHMARK(bm)->Apply(common_args); -BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); + +BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); BENCHMARK_MAIN();