From eecb0a4874b4ce2d8e3540abec93b30684d09f32 Mon Sep 17 00:00:00 2001 From: Denis Yaroshevskiy Date: Mon, 19 Aug 2024 08:45:23 -0700 Subject: [PATCH] folly simd-friendly (#2279) Summary: Pull Request resolved: https://github.com/facebook/folly/pull/2279 extracting the common "simd-friendly" type helpers. Differential Revision: D61205292 --- CMakeLists.txt | 3 +- folly/algorithm/simd/BUCK | 1 + folly/algorithm/simd/FindFixed.h | 14 +-- folly/algorithm/simd/detail/BUCK | 9 ++ folly/algorithm/simd/detail/Traits.h | 84 ++++++++++++++++++ folly/algorithm/simd/detail/test/BUCK | 10 +++ .../algorithm/simd/detail/test/TraitsTest.cpp | 86 +++++++++++++++++++ 7 files changed, 195 insertions(+), 12 deletions(-) create mode 100644 folly/algorithm/simd/detail/Traits.h create mode 100644 folly/algorithm/simd/detail/test/TraitsTest.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c58dedc4ef2..60419cb25ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -646,8 +646,9 @@ if (BUILD_TESTS OR BUILD_BENCHMARKS) folly_define_tests( DIRECTORY algorithm/simd/detail/test/ TEST simd_any_of_test SOURCES SimdAnyOfTest.cpp - TEST unroll_utils_test SOURCES UnrollUtilsTest.cpp TEST simd_for_each_test SOURCES SimdForEachTest.cpp + TEST simd_traits_test SOURCES TraitsTest.cpp + TEST unroll_utils_test SOURCES UnrollUtilsTest.cpp DIRECTORY algorithm/simd/test/ TEST find_fixed_test SOURCES FindFixedTest.cpp diff --git a/folly/algorithm/simd/BUCK b/folly/algorithm/simd/BUCK index c1057ab4e84..a660fce85ab 100644 --- a/folly/algorithm/simd/BUCK +++ b/folly/algorithm/simd/BUCK @@ -19,5 +19,6 @@ cpp_library( exported_deps = [ ":movemask", "//folly:portability", + "//folly/algorithm/simd/detail:traits", ], ) diff --git a/folly/algorithm/simd/FindFixed.h b/folly/algorithm/simd/FindFixed.h index c76c8022341..310752e9729 100644 --- a/folly/algorithm/simd/FindFixed.h +++ b/folly/algorithm/simd/FindFixed.h @@ -28,6 +28,7 @@ #include #include +#include #if FOLLY_X64 #include @@ -82,11 +83,6 @@ constexpr std::optional findFixed(std::span where, U x) // implementation --------------------------------------------------------- namespace find_fixed_detail { -template -std::optional findFixedCast(std::span& where, T x) { - std::span whereU{reinterpret_cast(where.data()), N}; - return findFixed(whereU, static_cast(x)); -} template constexpr std::optional findFixedConstexpr( @@ -295,13 +291,9 @@ constexpr std::optional findFixed(std::span where, U x) return findFixed(where, static_cast(x)); } else if (std::is_constant_evaluated()) { return find_fixed_detail::findFixedConstexpr(std::span(where), x); - } else if constexpr (std::is_enum_v) { - return find_fixed_detail::findFixedCast>( - where, x); - } else if constexpr (std::is_signed_v) { - return find_fixed_detail::findFixedCast>(where, x); } else { - return find_fixed_detail::findFixedDispatch(where, x); + return find_fixed_detail::findFixedDispatch( + detail::asSimdFriendly(where), detail::asSimdFriendly(x)); } } diff --git a/folly/algorithm/simd/detail/BUCK b/folly/algorithm/simd/detail/BUCK index c7501e203a1..2a1d4363a03 100644 --- a/folly/algorithm/simd/detail/BUCK +++ b/folly/algorithm/simd/detail/BUCK @@ -36,6 +36,15 @@ cpp_library( ], ) +cpp_library( + name = "traits", + headers = ["Traits.h"], + exported_deps = [ + "//folly:memory", + "//folly:traits", + ], +) + cpp_library( name = "unroll_utils", headers = ["UnrollUtils.h"], diff --git a/folly/algorithm/simd/detail/Traits.h b/folly/algorithm/simd/detail/Traits.h new file mode 100644 index 00000000000..eff1a1f5e4d --- /dev/null +++ b/folly/algorithm/simd/detail/Traits.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include +#include +#include + +namespace folly::detail { + +template +auto findSimdFriendlyEquivalent() { + if constexpr (std::is_enum_v) { + return findSimdFriendlyEquivalent>(); + } else if constexpr (std::is_floating_point_v) { + if constexpr (sizeof(T) == 4) { + return float{}; + } else { + return double{}; + } + } else if constexpr (std::is_signed_v) { + if constexpr (sizeof(T) == 1) { + return std::int8_t{}; + } else if constexpr (sizeof(T) == 2) { + return std::int16_t{}; + } else if constexpr (sizeof(T) == 4) { + return std::int32_t{}; + } else if constexpr (sizeof(T) == 8) { + return std::int64_t{}; + } + } else if constexpr (std::is_unsigned_v) { + if constexpr (sizeof(T) == 1) { + return std::uint8_t{}; + } else if constexpr (sizeof(T) == 2) { + return std::uint16_t{}; + } else if constexpr (sizeof(T) == 4) { + return std::uint32_t{}; + } else if constexpr (sizeof(T) == 8) { + return std::uint64_t{}; + } + } +} + +template +concept has_simd_friendly_equivalent = + !std::is_same_v())>; + +template +using simd_friendly_equivalent_t = folly::like_t< // + T, + decltype(findSimdFriendlyEquivalent>())>; + +template + requires std::integral +using integral_simd_friendly_equivalent = simd_friendly_equivalent_t; + +template +auto asSimdFriendly(std::span s) { + return folly::reinterpret_span_cast>(s); +} + +template +constexpr auto asSimdFriendly(T x) { + return static_cast>(x); +} + +} // namespace folly::detail diff --git a/folly/algorithm/simd/detail/test/BUCK b/folly/algorithm/simd/detail/test/BUCK index fe5871aa577..6661c2ce012 100644 --- a/folly/algorithm/simd/detail/test/BUCK +++ b/folly/algorithm/simd/detail/test/BUCK @@ -24,6 +24,16 @@ cpp_unittest( ], ) +cpp_unittest( + name = "traits_test", + srcs = ["TraitsTest.cpp"], + deps = [ + "//folly/algorithm/simd/detail:traits", + "//folly/portability:gmock", + "//folly/portability:gtest", + ], +) + cpp_unittest( name = "unroll_utils_test", srcs = [ diff --git a/folly/algorithm/simd/detail/test/TraitsTest.cpp b/folly/algorithm/simd/detail/test/TraitsTest.cpp new file mode 100644 index 00000000000..411702559f4 --- /dev/null +++ b/folly/algorithm/simd/detail/test/TraitsTest.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include + +namespace folly::detail { + +struct FollySimdTraitsTest : testing::Test {}; + +namespace simd_friendly_equivalent_test { + +// ints +static_assert( + std::is_same_v>); +static_assert( + std::is_same_v>); + +static_assert(std::is_same_v>); +static_assert( + std::is_same_v>); + +static_assert(std::is_same_v>); +static_assert( + std::is_same_v>); + +static_assert( + std::is_same_v>); +static_assert( + std::is_same_v>); + +// floats +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); + +// enum +enum SomeInt {}; +enum class SomeIntClass : std::int32_t {}; + +static_assert( + std::is_same_v>); +static_assert( + std::is_same_v>); + +// const + +static_assert( + std::is_same_v>); + +// sfinae +constexpr auto sfinae_call = + [](T) -> simd_friendly_equivalent_t { return {}; }; + +static_assert(std::invocable); + +struct NotSimdFriendly {}; +static_assert(!std::invocable); + +} // namespace simd_friendly_equivalent_test + +TEST_F(FollySimdTraitsTest, AsSimdFriendly) { + enum SomeEnum : int { Foo = 1, Bar, Baz }; + + static_assert(asSimdFriendly(SomeEnum::Foo) == 1); + + std::array arr{SomeEnum::Foo, SomeEnum::Bar, SomeEnum::Baz}; + std::span castSpan = asSimdFriendly(std::span(arr)); + ASSERT_THAT(castSpan, testing::ElementsAre(1, 2, 3)); +} + +} // namespace folly::detail