Skip to content

Commit

Permalink
folly simd-friendly (#2279)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #2279

extracting the common "simd-friendly" type helpers.

Differential Revision: D61205292
  • Loading branch information
DenisYaroshevskiy authored and facebook-github-bot committed Aug 14, 2024
1 parent 53ffd56 commit d275d4c
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 12 deletions.
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 traits_test SOURCES TraitsTest.cpp
TEST unroll_utils_test SOURCES UnrollUtilsTest.cpp

DIRECTORY algorithm/simd/test/
TEST find_fixed_test SOURCES FindFixedTest.cpp
Expand Down
1 change: 1 addition & 0 deletions folly/algorithm/simd/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ cpp_library(
exported_deps = [
":movemask",
"//folly:portability",
"//folly/algorithm/simd/detail:traits",
],
)
14 changes: 3 additions & 11 deletions folly/algorithm/simd/FindFixed.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

#include <folly/Portability.h>
#include <folly/algorithm/simd/Movemask.h>
#include <folly/algorithm/simd/detail/Traits.h>

#if FOLLY_X64
#include <immintrin.h>
Expand Down Expand Up @@ -82,11 +83,6 @@ constexpr std::optional<std::size_t> findFixed(std::span<const T, N> where, U x)
// implementation ---------------------------------------------------------

namespace find_fixed_detail {
template <typename U, typename T, std::size_t N>
std::optional<std::size_t> findFixedCast(std::span<const T, N>& where, T x) {
std::span<const U, N> whereU{reinterpret_cast<const U*>(where.data()), N};
return findFixed(whereU, static_cast<U>(x));
}

template <typename T>
constexpr std::optional<std::size_t> findFixedConstexpr(
Expand Down Expand Up @@ -295,13 +291,9 @@ constexpr std::optional<std::size_t> findFixed(std::span<const T, N> where, U x)
return findFixed(where, static_cast<T>(x));
} else if (std::is_constant_evaluated()) {
return find_fixed_detail::findFixedConstexpr(std::span<const T>(where), x);
} else if constexpr (std::is_enum_v<T>) {
return find_fixed_detail::findFixedCast<std::underlying_type_t<T>>(
where, x);
} else if constexpr (std::is_signed_v<T>) {
return find_fixed_detail::findFixedCast<std::make_unsigned_t<T>>(where, x);
} else {
return find_fixed_detail::findFixedDispatch(where, x);
return find_fixed_detail::findFixedDispatch(
detail::asSimdFriendly(where), detail::asSimdFriendly(x));
}
}

Expand Down
8 changes: 8 additions & 0 deletions folly/algorithm/simd/detail/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ cpp_library(
],
)

cpp_library(
name = "traits",
headers = ["Traits.h"],
exported_deps = [
"//folly:memory",
],
)

cpp_library(
name = "unroll_utils",
headers = ["UnrollUtils.h"],
Expand Down
95 changes: 95 additions & 0 deletions folly/algorithm/simd/detail/Traits.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* 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 <folly/Memory.h>

#include <concepts>
#include <span>
#include <type_traits>

namespace folly::detail {

struct regular_nonesuch {};

template <typename T>
auto findSimdFriendlyEquivalent() {
if constexpr (std::is_enum_v<T>) {
return findSimdFriendlyEquivalent<std::underlying_type_t<T>>();
} else if constexpr (std::is_floating_point_v<T>) {
if constexpr (sizeof(T) == 4) {
return float{};
} else {
return double{};
}
} else if constexpr (std::is_signed_v<T>) {
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 {
return regular_nonesuch{};
}
} else if constexpr (std::is_unsigned_v<T>) {
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{};
} else {
return regular_nonesuch{};
}
} else {
return regular_nonesuch{};
}
}

template <bool Cond, typename To>
using add_const_if_t = std::conditional_t<Cond, const To, To>;

template <typename T>
concept has_simd_friendly_equivalent =
!std::
is_same_v<regular_nonesuch, decltype(findSimdFriendlyEquivalent<T>())>;

template <has_simd_friendly_equivalent T>
using simd_friendly_equivalent_t = add_const_if_t<
std::is_const_v<T>,
decltype(findSimdFriendlyEquivalent<std::remove_const_t<T>>())>;

template <has_simd_friendly_equivalent T>
requires std::integral<T>
using integral_simd_friendly_equivalent = simd_friendly_equivalent_t<T>;

template <has_simd_friendly_equivalent T, std::size_t Extend>
auto asSimdFriendly(std::span<T, Extend> s) {
return folly::reinterpret_span_cast<simd_friendly_equivalent_t<T>>(s);
}

template <has_simd_friendly_equivalent T>
constexpr auto asSimdFriendly(T x) {
return static_cast<simd_friendly_equivalent_t<T>>(x);
}

} // namespace folly::detail
10 changes: 10 additions & 0 deletions folly/algorithm/simd/detail/test/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand Down
88 changes: 88 additions & 0 deletions folly/algorithm/simd/detail/test/TraitsTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* 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 <folly/algorithm/simd/detail/Traits.h>

#include <folly/portability/GMock.h>
#include <folly/portability/GTest.h>

namespace folly::detail {

TEST(FollySimdTraits, SimdFriendlyEquivalent) {
// ints
static_assert(
std::is_same_v<std::int8_t, simd_friendly_equivalent_t<signed char>>);
static_assert(
std::is_same_v<std::uint8_t, simd_friendly_equivalent_t<unsigned char>>);

static_assert(
std::is_same_v<std::int16_t, simd_friendly_equivalent_t<short>>);
static_assert(
std::
is_same_v<std::uint16_t, simd_friendly_equivalent_t<unsigned short>>);

static_assert(std::is_same_v<std::int32_t, simd_friendly_equivalent_t<int>>);
static_assert(
std::is_same_v<std::uint32_t, simd_friendly_equivalent_t<unsigned int>>);

static_assert(
std::is_same_v<std::int64_t, simd_friendly_equivalent_t<std::int64_t>>);
static_assert(
std::is_same_v<std::uint64_t, simd_friendly_equivalent_t<std::uint64_t>>);

// floats
static_assert(std::is_same_v<float, simd_friendly_equivalent_t<float>>);
static_assert(std::is_same_v<double, simd_friendly_equivalent_t<double>>);

// enum
enum SomeInt {};
enum class SomeIntClass : std::int32_t {};

static_assert(
std::is_same_v<std::uint32_t, simd_friendly_equivalent_t<SomeInt>>);
static_assert(
std::is_same_v<std::int32_t, simd_friendly_equivalent_t<SomeIntClass>>);

// const

static_assert(
std::
is_same_v<const std::int32_t, simd_friendly_equivalent_t<const int>>);

// sfinae
{
auto call = []<typename T>(T) -> simd_friendly_equivalent_t<T> {
return {};
};

static_assert(std::invocable<decltype(call), int>);

struct NotSimdFriendly {};
static_assert(!std::invocable<decltype(call), NotSimdFriendly>);
}
}

TEST(FollySimdTraits, 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<int, 3> castSpan = asSimdFriendly(std::span(arr));
ASSERT_THAT(castSpan, testing::ElementsAre(1, 2, 3));
}

} // namespace folly::detail

0 comments on commit d275d4c

Please sign in to comment.