File indexing completed on 2025-08-28 09:11:38
0001
0002
0003
0004
0005
0006
0007
0008
0009
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
0028
0029
0030
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
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 }
0087
0088
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
0115 return detail::max_of(Archs::alignment()..., static_cast<size_t>(0));
0116 }
0117 };
0118
0119 namespace detail
0120 {
0121
0122
0123
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
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 }
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, 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
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 }
0237
0238 #endif