File indexing completed on 2025-01-30 10:25:58
0001 #ifndef VECCORE_BACKEND_STD_SIMD_H
0002 #define VECCORE_BACKEND_STD_SIMD_H
0003
0004 #if __cplusplus >= 202002L && defined(__has_include)
0005 #if __has_include(<experimental/simd>)
0006 #define VECCORE_ENABLE_STD_SIMD
0007 #endif
0008 #endif
0009
0010 #ifdef VECCORE_ENABLE_STD_SIMD
0011
0012 #include <experimental/simd>
0013
0014 namespace vecCore {
0015
0016 template <typename T, class Abi>
0017 struct TypeTraits<std::experimental::simd_mask<T, Abi>> {
0018 using IndexType = typename std::experimental::simd_mask<T, Abi>::simd_type;
0019 using ScalarType = typename std::experimental::simd_mask<T, Abi>::value_type;
0020 static constexpr size_t Size = std::experimental::simd<T, Abi>::size();
0021 };
0022
0023 template <typename T, class Abi>
0024 struct TypeTraits<std::experimental::simd<T, Abi>> {
0025 using MaskType = typename std::experimental::simd<T, Abi>::mask_type;
0026 using IndexType = typename std::experimental::simd<T, Abi>;
0027 using ScalarType = typename std::experimental::simd<T, Abi>::value_type;
0028 static constexpr size_t Size = std::experimental::simd<T, Abi>::size();
0029 };
0030
0031 namespace backend {
0032
0033 template <class Abi> class SIMD {
0034 public:
0035 using Real_v = std::experimental::simd<Real_s, Abi>;
0036 using Float_v = std::experimental::simd<float, Abi>;
0037 using Double_v = std::experimental::simd<double, Abi>;
0038
0039 using Int_v = std::experimental::simd<int, Abi>;
0040 using Int16_v = std::experimental::simd<int16_t, Abi>;
0041 using Int32_v = std::experimental::simd<int32_t, Abi>;
0042 using Int64_v = std::experimental::simd<int64_t, Abi>;
0043
0044 using UInt_v = std::experimental::simd<unsigned int, Abi>;
0045 using UInt16_v = std::experimental::simd<uint16_t, Abi>;
0046 using UInt32_v = std::experimental::simd<uint32_t, Abi>;
0047 using UInt64_v = std::experimental::simd<uint64_t, Abi>;
0048 };
0049
0050 class SIMDNative {
0051 public:
0052 using Real_v = std::experimental::native_simd<Real_s>;
0053 using Float_v = std::experimental::native_simd<float>;
0054 using Double_v = std::experimental::native_simd<double>;
0055
0056 using Int_v = std::experimental::native_simd<int>;
0057 using Int16_v = std::experimental::native_simd<int16_t>;
0058 using Int32_v = std::experimental::native_simd<int32_t>;
0059 using Int64_v = std::experimental::native_simd<int64_t>;
0060
0061 using UInt_v = std::experimental::native_simd<unsigned int>;
0062 using UInt16_v = std::experimental::native_simd<uint16_t>;
0063 using UInt32_v = std::experimental::native_simd<uint32_t>;
0064 using UInt64_v = std::experimental::native_simd<uint64_t>;
0065 };
0066
0067 using SIMDScalar = SIMD<std::experimental::simd_abi::scalar>;
0068
0069 template <size_t N>
0070 using SIMDVector = SIMD<std::experimental::simd_abi::fixed_size<N>>;
0071
0072 }
0073
0074 template <typename T, class Abi>
0075 bool MaskEmpty(std::experimental::simd_mask<T, Abi> mask) {
0076 for (int i = 0; i < mask.size(); ++i)
0077 if (mask[i])
0078 return false;
0079 return true;
0080 }
0081
0082 template <typename T, class Abi>
0083 bool MaskFull(std::experimental::simd_mask<T, Abi> mask) {
0084 for (int i = 0; i < mask.size(); ++i)
0085 if (!mask[i])
0086 return false;
0087 return true;
0088 }
0089
0090 template <typename T, class Abi>
0091 struct IndexingImplementation<std::experimental::simd<T, Abi>> {
0092 using V = std::experimental::simd<T, Abi>;
0093
0094 static inline T Get(const V &v, size_t i) { return v[i]; }
0095 static inline void Set(V &v, size_t i, T const val) { v[i] = val; }
0096 };
0097
0098 template <typename T, class Abi>
0099 struct IndexingImplementation<std::experimental::simd_mask<T, Abi>> {
0100 using V = std::experimental::simd_mask<T, Abi>;
0101
0102 static inline T Get(const V &v, size_t i) { return v[i]; }
0103 static inline void Set(V &v, size_t i, T const val) { v[i] = !!val; }
0104 };
0105
0106 template <typename T, class Abi>
0107 struct LoadStoreImplementation<std::experimental::simd<T, Abi>> {
0108 using V = std::experimental::simd<T, Abi>;
0109
0110 template <typename S = T> static inline void Load(V &v, S const *ptr) {
0111 for (size_t i = 0; i < V::size(); ++i)
0112 v[i] = ptr[i];
0113 }
0114
0115 template <typename S = T> static inline void Store(V const &v, S *ptr) {
0116 for (size_t i = 0; i < V::size(); ++i)
0117 ptr[i] = static_cast<S>(v[i]);
0118 }
0119 };
0120
0121 template <typename T, class Abi>
0122 struct LoadStoreImplementation<std::experimental::simd_mask<T, Abi>> {
0123 using V = typename std::experimental::simd_mask<T, Abi>;
0124
0125 template <typename S = T> static inline void Load(V &v, S const *ptr) {
0126 for (size_t i = 0; i < V::size(); ++i)
0127 v[i] = !!ptr[i];
0128 }
0129
0130 template <typename S = T> static inline void Store(V const &v, S *ptr) {
0131 for (size_t i = 0; i < V::size(); ++i)
0132 ptr[i] = static_cast<S>(v[i]);
0133 }
0134 };
0135
0136 template <typename T, class Abi>
0137 struct MaskingImplementation<std::experimental::simd<T, Abi>> {
0138 using V = typename std::experimental::simd<T, Abi>;
0139 using M = typename std::experimental::simd<T, Abi>::mask_type;
0140
0141 static inline void Assign(V &dst, M const &mask, V const &src) {
0142 where(mask, dst) = src;
0143 }
0144
0145 static inline void Blend(V &dst, M const &mask, V const &src1,
0146 V const &src2) {
0147 where(mask, dst) = src1;
0148 where(!mask, dst) = src2;
0149 }
0150 };
0151
0152 template <class Abi>
0153 struct GatherScatterImplementation<std::experimental::simd<float, Abi>> {
0154 using V = typename std::experimental::simd<float, Abi>;
0155
0156 template <typename S = float>
0157 static inline void Gather(V &v, S const *ptr, V const &idx) {
0158 auto ii = std::experimental::static_simd_cast<int, float, Abi>(idx);
0159 for (size_t i = 0; i < V::size(); ++i)
0160 v[i] = ptr[ii[i]];
0161 }
0162
0163 template <typename S = float>
0164 static inline void Scatter(V const &v, S *ptr, V const &idx) {
0165 auto ii = std::experimental::static_simd_cast<int, float, Abi>(idx);
0166 for (size_t i = 0; i < V::size(); ++i)
0167 ptr[ii[i]] = v[i];
0168 }
0169 };
0170
0171 template <class Abi>
0172 struct GatherScatterImplementation<std::experimental::simd<double, Abi>> {
0173 using V = typename std::experimental::simd<double, Abi>;
0174
0175 template <typename S = double>
0176 static inline void Gather(V &v, S const *ptr, V const &idx) {
0177 auto ii = std::experimental::static_simd_cast<int64_t, double, Abi>(idx);
0178 for (size_t i = 0; i < V::size(); ++i)
0179 v[i] = ptr[ii[i]];
0180 }
0181
0182 template <typename S = double>
0183 static inline void Scatter(V const &v, S *ptr, V const &idx) {
0184 auto ii = std::experimental::static_simd_cast<int64_t, double, Abi>(idx);
0185 for (size_t i = 0; i < V::size(); ++i)
0186 ptr[ii[i]] = v[i];
0187 }
0188 };
0189
0190 }
0191
0192 #endif
0193 #endif