summaryrefslogtreecommitdiffstats
path: root/third_party/xsimd/include/xsimd/config/xsimd_arch.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/xsimd/include/xsimd/config/xsimd_arch.hpp')
-rw-r--r--third_party/xsimd/include/xsimd/config/xsimd_arch.hpp264
1 files changed, 264 insertions, 0 deletions
diff --git a/third_party/xsimd/include/xsimd/config/xsimd_arch.hpp b/third_party/xsimd/include/xsimd/config/xsimd_arch.hpp
new file mode 100644
index 0000000000..575459a009
--- /dev/null
+++ b/third_party/xsimd/include/xsimd/config/xsimd_arch.hpp
@@ -0,0 +1,264 @@
+/***************************************************************************
+ * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and *
+ * Martin Renou *
+ * Copyright (c) QuantStack *
+ * Copyright (c) Serge Guelton *
+ * *
+ * Distributed under the terms of the BSD 3-Clause License. *
+ * *
+ * The full license is in the file LICENSE, distributed with this software. *
+ ****************************************************************************/
+
+#ifndef XSIMD_ARCH_HPP
+#define XSIMD_ARCH_HPP
+
+#include <initializer_list>
+#include <type_traits>
+#include <utility>
+
+#include "../types/xsimd_all_registers.hpp"
+#include "./xsimd_config.hpp"
+#include "./xsimd_cpuid.hpp"
+
+namespace xsimd
+{
+
+ /**
+ * @ingroup architectures
+ *
+ * Dummy architectures that only appears in a list of architecture when no
+ * other architecture has been detected.
+ */
+ struct unavailable
+ {
+ static constexpr bool supported() noexcept { return false; }
+ static constexpr bool available() noexcept { return false; }
+ static constexpr unsigned version() noexcept { return 0; }
+ static constexpr std::size_t alignment() noexcept { return 0; }
+ static constexpr bool requires_alignment() noexcept { return false; }
+ static constexpr char const* name() noexcept { return "<none>"; }
+ };
+
+ namespace detail
+ {
+ // Checks whether T appears in Tys.
+ template <class T, class... Tys>
+ struct contains;
+
+ template <class T>
+ struct contains<T> : std::false_type
+ {
+ };
+
+ template <class T, class Ty, class... Tys>
+ struct contains<T, Ty, Tys...>
+ : std::conditional<std::is_same<Ty, T>::value, std::true_type,
+ contains<T, Tys...>>::type
+ {
+ };
+
+ template <unsigned... Vals>
+ struct is_sorted;
+
+ template <>
+ struct is_sorted<> : std::true_type
+ {
+ };
+
+ template <unsigned Val>
+ struct is_sorted<Val> : std::true_type
+ {
+ };
+
+ template <unsigned V0, unsigned V1, unsigned... Vals>
+ struct is_sorted<V0, V1, Vals...>
+ : std::conditional<(V0 >= V1), is_sorted<V1, Vals...>,
+ std::false_type>::type
+ {
+ };
+
+ template <typename T>
+ inline constexpr T max_of(T value) noexcept
+ {
+ return value;
+ }
+
+ template <typename T, typename... Ts>
+ inline constexpr T max_of(T head0, T head1, Ts... tail) noexcept
+ {
+ return max_of((head0 > head1 ? head0 : head1), tail...);
+ }
+
+ template <typename... Ts>
+ struct head;
+
+ template <typename T, typename... Ts>
+ struct head<T, Ts...>
+ {
+ using type = T;
+ };
+
+ template <>
+ struct head<>
+ {
+ using type = unavailable;
+ };
+
+ } // namespace detail
+
+ // An arch_list is a list of architectures, sorted by version number.
+ template <class... Archs>
+ struct arch_list
+ {
+#ifndef NDEBUG
+ static_assert(detail::is_sorted<Archs::version()...>::value,
+ "architecture list must be sorted by version");
+#endif
+
+ using best = typename detail::head<Archs...>::type;
+
+ template <class Arch>
+ using add = arch_list<Archs..., Arch>;
+
+ template <class... OtherArchs>
+ using extend = arch_list<Archs..., OtherArchs...>;
+
+ template <class Arch>
+ static constexpr bool contains() noexcept
+ {
+ return detail::contains<Arch, Archs...>::value;
+ }
+
+ template <class F>
+ static inline void for_each(F&& f) noexcept
+ {
+ (void)std::initializer_list<bool> { (f(Archs {}), true)... };
+ }
+
+ static constexpr std::size_t alignment() noexcept
+ {
+ // all alignments are a power of two
+ return detail::max_of(Archs::alignment()..., static_cast<size_t>(0));
+ }
+ };
+
+ namespace detail
+ {
+
+ // Filter archlists Archs, picking only supported archs and adding
+ // them to L.
+ template <class L, class... Archs>
+ struct supported_helper;
+
+ template <class L>
+ struct supported_helper<L, arch_list<>>
+ {
+ using type = L;
+ };
+
+ template <class L, class Arch, class... Archs>
+ struct supported_helper<L, arch_list<Arch, Archs...>>
+ : supported_helper<
+ typename std::conditional<Arch::supported(),
+ typename L::template add<Arch>, L>::type,
+ arch_list<Archs...>>
+ {
+ };
+
+ template <class... Archs>
+ struct supported : supported_helper<arch_list<>, Archs...>
+ {
+ };
+
+ // Joins all arch_list Archs in a single arch_list.
+ template <class... Archs>
+ struct join;
+
+ template <class Arch>
+ struct join<Arch>
+ {
+ using type = Arch;
+ };
+
+ template <class Arch, class... Archs, class... Args>
+ struct join<Arch, arch_list<Archs...>, Args...>
+ : join<typename Arch::template extend<Archs...>, Args...>
+ {
+ };
+ } // namespace detail
+
+ using all_x86_architectures = arch_list<
+ avx512vnni<avx512vbmi>, avx512vbmi, avx512ifma, avx512pf, avx512vnni<avx512bw>, avx512bw, avx512er, avx512dq, avx512cd, avx512f,
+ avxvnni, fma3<avx2>, avx2, fma3<avx>, avx, fma4, fma3<sse4_2>,
+ sse4_2, sse4_1, /*sse4a,*/ ssse3, sse3, sse2>;
+
+ using all_sve_architectures = arch_list<detail::sve<512>, detail::sve<256>, detail::sve<128>>;
+ using all_rvv_architectures = arch_list<detail::rvv<512>, detail::rvv<256>, detail::rvv<128>>;
+ using all_arm_architectures = typename detail::join<all_sve_architectures, arch_list<neon64, neon>>::type;
+ using all_riscv_architectures = all_rvv_architectures;
+ using all_wasm_architectures = arch_list<wasm>;
+ using all_architectures = typename detail::join<all_riscv_architectures, all_wasm_architectures, all_arm_architectures, all_x86_architectures>::type;
+
+ using supported_architectures = typename detail::supported<all_architectures>::type;
+
+ using x86_arch = typename detail::supported<all_x86_architectures>::type::best;
+ using arm_arch = typename detail::supported<all_arm_architectures>::type::best;
+ using riscv_arch = typename detail::supported<all_riscv_architectures>::type::best;
+ using best_arch = typename supported_architectures::best;
+
+#ifdef XSIMD_DEFAULT_ARCH
+ using default_arch = XSIMD_DEFAULT_ARCH;
+#else
+ using default_arch = best_arch;
+#endif
+
+ namespace detail
+ {
+ template <class F, class ArchList>
+ class dispatcher
+ {
+
+ const decltype(available_architectures()) availables_archs;
+ F functor;
+
+ template <class Arch, class... Tys>
+ inline auto walk_archs(arch_list<Arch>, Tys&&... args) noexcept -> decltype(functor(Arch {}, std::forward<Tys>(args)...))
+ {
+ assert(Arch::available() && "At least one arch must be supported during dispatch");
+ return functor(Arch {}, std::forward<Tys>(args)...);
+ }
+
+ template <class Arch, class ArchNext, class... Archs, class... Tys>
+ inline auto walk_archs(arch_list<Arch, ArchNext, Archs...>, Tys&&... args) noexcept -> decltype(functor(Arch {}, std::forward<Tys>(args)...))
+ {
+ if (availables_archs.has(Arch {}))
+ return functor(Arch {}, std::forward<Tys>(args)...);
+ else
+ return walk_archs(arch_list<ArchNext, Archs...> {}, std::forward<Tys>(args)...);
+ }
+
+ public:
+ inline dispatcher(F f) noexcept
+ : availables_archs(available_architectures())
+ , functor(f)
+ {
+ }
+
+ template <class... Tys>
+ inline auto operator()(Tys&&... args) noexcept -> decltype(functor(default_arch {}, std::forward<Tys>(args)...))
+ {
+ return walk_archs(ArchList {}, std::forward<Tys>(args)...);
+ }
+ };
+ }
+
+ // Generic function dispatch, à la ifunc
+ template <class ArchList = supported_architectures, class F>
+ inline detail::dispatcher<F, ArchList> dispatch(F&& f) noexcept
+ {
+ return { std::forward<F>(f) };
+ }
+
+} // namespace xsimd
+
+#endif