Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-08-28 09:11:38

0001 /***************************************************************************
0002  * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and         *
0003  * Martin Renou                                                             *
0004  * Copyright (c) QuantStack                                                 *
0005  * Copyright (c) Serge Guelton                                              *
0006  *                                                                          *
0007  * Distributed under the terms of the BSD 3-Clause License.                 *
0008  *                                                                          *
0009  * The full license is in the file LICENSE, distributed with this software. *
0010  ****************************************************************************/
0011 
0012 #ifndef XSIMD_ARCH_HPP
0013 #define XSIMD_ARCH_HPP
0014 
0015 #include <initializer_list>
0016 #include <type_traits>
0017 #include <utility>
0018 
0019 #include "../types/xsimd_all_registers.hpp"
0020 #include "./xsimd_config.hpp"
0021 #include "./xsimd_cpuid.hpp"
0022 
0023 namespace xsimd
0024 {
0025 
0026     /**
0027      * @ingroup architectures
0028      *
0029      * Dummy architectures that only appears in a list of architecture when no
0030      * other architecture has been detected.
0031      */
0032     struct unavailable
0033     {
0034         static constexpr bool supported() noexcept { return false; }
0035         static constexpr bool available() noexcept { return false; }
0036         static constexpr std::size_t alignment() noexcept { return 0; }
0037         static constexpr bool requires_alignment() noexcept { return false; }
0038         static constexpr char const* name() noexcept { return "<none>"; }
0039     };
0040 
0041     namespace detail
0042     {
0043         // Checks whether T appears in Tys.
0044         template <class T, class... Tys>
0045         struct contains;
0046 
0047         template <class T>
0048         struct contains<T> : std::false_type
0049         {
0050         };
0051 
0052         template <class T, class Ty, class... Tys>
0053         struct contains<T, Ty, Tys...>
0054             : std::conditional<std::is_same<Ty, T>::value, std::true_type,
0055                                contains<T, Tys...>>::type
0056         {
0057         };
0058 
0059         template <typename T>
0060         XSIMD_INLINE constexpr T max_of(T value) noexcept
0061         {
0062             return value;
0063         }
0064 
0065         template <typename T, typename... Ts>
0066         XSIMD_INLINE constexpr T max_of(T head0, T head1, Ts... tail) noexcept
0067         {
0068             return max_of((head0 > head1 ? head0 : head1), tail...);
0069         }
0070 
0071         template <typename... Ts>
0072         struct head;
0073 
0074         template <typename T, typename... Ts>
0075         struct head<T, Ts...>
0076         {
0077             using type = T;
0078         };
0079 
0080         template <>
0081         struct head<>
0082         {
0083             using type = unavailable;
0084         };
0085 
0086     } // namespace detail
0087 
0088     // An arch_list is a list of architectures.
0089     template <class... Archs>
0090     struct arch_list
0091     {
0092         using best = typename detail::head<Archs...>::type;
0093 
0094         template <class Arch>
0095         using add = arch_list<Archs..., Arch>;
0096 
0097         template <class... OtherArchs>
0098         using extend = arch_list<Archs..., OtherArchs...>;
0099 
0100         template <class Arch>
0101         static constexpr bool contains() noexcept
0102         {
0103             return detail::contains<Arch, Archs...>::value;
0104         }
0105 
0106         template <class F>
0107         static XSIMD_INLINE void for_each(F&& f) noexcept
0108         {
0109             (void)std::initializer_list<bool> { (f(Archs {}), true)... };
0110         }
0111 
0112         static constexpr std::size_t alignment() noexcept
0113         {
0114             // all alignments are a power of two
0115             return detail::max_of(Archs::alignment()..., static_cast<size_t>(0));
0116         }
0117     };
0118 
0119     namespace detail
0120     {
0121 
0122         // Filter archlists Archs, picking only supported archs and adding
0123         // them to L.
0124         template <class L, class... Archs>
0125         struct supported_helper;
0126 
0127         template <class L>
0128         struct supported_helper<L, arch_list<>>
0129         {
0130             using type = L;
0131         };
0132 
0133         template <class L, class Arch, class... Archs>
0134         struct supported_helper<L, arch_list<Arch, Archs...>>
0135             : supported_helper<
0136                   typename std::conditional<Arch::supported(),
0137                                             typename L::template add<Arch>, L>::type,
0138                   arch_list<Archs...>>
0139         {
0140         };
0141 
0142         template <class... Archs>
0143         struct supported : supported_helper<arch_list<>, Archs...>
0144         {
0145         };
0146 
0147         // Joins all arch_list Archs in a single arch_list.
0148         template <class... Archs>
0149         struct join;
0150 
0151         template <class Arch>
0152         struct join<Arch>
0153         {
0154             using type = Arch;
0155         };
0156 
0157         template <class Arch, class... Archs, class... Args>
0158         struct join<Arch, arch_list<Archs...>, Args...>
0159             : join<typename Arch::template extend<Archs...>, Args...>
0160         {
0161         };
0162     } // namespace detail
0163 
0164     using all_x86_architectures = arch_list<
0165         avx512vnni<avx512vbmi>, avx512vbmi, avx512ifma, avx512pf, avx512vnni<avx512bw>, avx512bw, avx512er, avx512dq, avx512cd, avx512f,
0166         avxvnni, fma3<avx2>, avx2, fma3<avx>, avx, fma4, fma3<sse4_2>,
0167         sse4_2, sse4_1, /*sse4a,*/ ssse3, sse3, sse2>;
0168 
0169     using all_sve_architectures = arch_list<detail::sve<512>, detail::sve<256>, detail::sve<128>>;
0170     using all_rvv_architectures = arch_list<detail::rvv<512>, detail::rvv<256>, detail::rvv<128>>;
0171     using all_arm_architectures = typename detail::join<all_sve_architectures, arch_list<i8mm<neon64>, neon64, neon>>::type;
0172     using all_riscv_architectures = all_rvv_architectures;
0173     using all_wasm_architectures = arch_list<wasm>;
0174     using all_architectures = typename detail::join<all_riscv_architectures, all_wasm_architectures, all_arm_architectures, all_x86_architectures>::type;
0175 
0176     using supported_architectures = typename detail::supported<all_architectures>::type;
0177 
0178     using x86_arch = typename detail::supported<all_x86_architectures>::type::best;
0179     using arm_arch = typename detail::supported<all_arm_architectures>::type::best;
0180     using riscv_arch = typename detail::supported<all_riscv_architectures>::type::best;
0181     using best_arch = typename supported_architectures::best;
0182 
0183 #ifdef XSIMD_DEFAULT_ARCH
0184     using default_arch = XSIMD_DEFAULT_ARCH;
0185 #else
0186     using default_arch = best_arch;
0187 #endif
0188 
0189     namespace detail
0190     {
0191         template <class F, class ArchList>
0192         class dispatcher
0193         {
0194 
0195             const decltype(available_architectures()) availables_archs;
0196             F functor;
0197 
0198             template <class Arch, class... Tys>
0199             XSIMD_INLINE auto walk_archs(arch_list<Arch>, Tys&&... args) noexcept -> decltype(functor(Arch {}, std::forward<Tys>(args)...))
0200             {
0201                 assert(Arch::available() && "At least one arch must be supported during dispatch");
0202                 return functor(Arch {}, std::forward<Tys>(args)...);
0203             }
0204 
0205             template <class Arch, class ArchNext, class... Archs, class... Tys>
0206             XSIMD_INLINE auto walk_archs(arch_list<Arch, ArchNext, Archs...>, Tys&&... args) noexcept -> decltype(functor(Arch {}, std::forward<Tys>(args)...))
0207             {
0208                 if (availables_archs.has(Arch {}))
0209                     return functor(Arch {}, std::forward<Tys>(args)...);
0210                 else
0211                     return walk_archs(arch_list<ArchNext, Archs...> {}, std::forward<Tys>(args)...);
0212             }
0213 
0214         public:
0215             XSIMD_INLINE dispatcher(F f) noexcept
0216                 : availables_archs(available_architectures())
0217                 , functor(f)
0218             {
0219             }
0220 
0221             template <class... Tys>
0222             XSIMD_INLINE auto operator()(Tys&&... args) noexcept -> decltype(functor(default_arch {}, std::forward<Tys>(args)...))
0223             {
0224                 return walk_archs(ArchList {}, std::forward<Tys>(args)...);
0225             }
0226         };
0227     }
0228 
0229     // Generic function dispatch, à la ifunc
0230     template <class ArchList = supported_architectures, class F>
0231     XSIMD_INLINE detail::dispatcher<F, ArchList> dispatch(F&& f) noexcept
0232     {
0233         return { std::forward<F>(f) };
0234     }
0235 
0236 } // namespace xsimd
0237 
0238 #endif