Back to home page

EIC code displayed by LXR

 
 

    


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 } // namespace backend
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 } // namespace vecCore
0191 
0192 #endif
0193 #endif