SIMDConvert.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. // Copyright (c) 2020 Nicholas Corgan
  2. // SPDX-License-Identifier: BSL-1.0
  3. #include "SIMDConvert.hpp"
  4. #include <Pothos/Framework.hpp>
  5. #include <Pothos/Util/Templates.hpp>
  6. #include <Pothos/Util/TypeInfo.hpp>
  7. #include <simdpp/simd.h>
  8. #include <simdpp/dispatch/get_arch_gcc_builtin_cpu_supports.h>
  9. #include <simdpp/dispatch/get_arch_raw_cpuid.h>
  10. #include <simdpp/dispatch/get_arch_linux_cpuinfo.h>
  11. #include <complex>
  12. #include <cstring>
  13. #include <type_traits>
  14. // SIMDPP_USER_ARCH_INFO used by SIMDPP_MAKE_DISPATCHER below
  15. #if SIMDPP_HAS_GET_ARCH_RAW_CPUID
  16. #define SIMDPP_USER_ARCH_INFO ::simdpp::get_arch_raw_cpuid()
  17. #elif SIMDPP_HAS_GET_ARCH_GCC_BUILTIN_CPU_SUPPORTS
  18. #define SIMDPP_USER_ARCH_INFO ::simdpp::get_arch_gcc_builtin_cpu_supports()
  19. #elif SIMDPP_HAS_GET_ARCH_LINUX_CPUINFO
  20. #define SIMDPP_USER_ARCH_INFO ::simdpp::get_arch_linux_cpuinfo()
  21. #else
  22. #error "Unsupported platform"
  23. #endif
  24. namespace SIMDPP_ARCH_NAMESPACE {
  25. namespace detail
  26. {
  27. /*
  28. * Make SFINAE structs out of arch-dependent #defines. Each copy
  29. * of this file will be compiled with different compiler flags,
  30. * so this SFINAE will behave as needed for each arch.
  31. */
  32. template <typename T>
  33. struct SIMDTraits
  34. {
  35. static constexpr bool Supported = false;
  36. template <typename OutType>
  37. static constexpr bool canConvertTo() {return false;}
  38. };
  39. template <>
  40. struct SIMDTraits<char>
  41. {
  42. static constexpr size_t FastSize = SIMDPP_FAST_INT8_SIZE;
  43. template <size_t N>
  44. using SIMDPPType = simdpp::int8<N>;
  45. using FastType = SIMDPPType<FastSize>;
  46. // Depends on instruction set
  47. static constexpr bool Supported = SIMDPP_HAS_INT8_SIMD;
  48. template <typename OutType>
  49. static constexpr bool canConvertTo() {return true;}
  50. template <typename InType>
  51. static SIMDPPType<SIMDTraits<InType>::FastSize> convertFromFastType(typename SIMDTraits<InType>::FastType inReg)
  52. {
  53. simdpp::int8<SIMDTraits<InType>::FastSize> outReg = simdpp::to_int8(inReg);
  54. return outReg;
  55. }
  56. };
  57. template <>
  58. struct SIMDTraits<int8_t>
  59. {
  60. static constexpr size_t FastSize = SIMDPP_FAST_INT8_SIZE;
  61. template <size_t N>
  62. using SIMDPPType = simdpp::int8<N>;
  63. using FastType = SIMDPPType<FastSize>;
  64. // Depends on instruction set
  65. static constexpr bool Supported = SIMDPP_HAS_INT8_SIMD;
  66. template <typename OutType>
  67. static constexpr bool canConvertTo() {return true;}
  68. template <typename InType>
  69. static SIMDPPType<SIMDTraits<InType>::FastSize> convertFromFastType(typename SIMDTraits<InType>::FastType inReg)
  70. {
  71. simdpp::int8<SIMDTraits<InType>::FastSize> outReg = simdpp::to_int8(inReg);
  72. return outReg;
  73. }
  74. };
  75. template <>
  76. struct SIMDTraits<int16_t>
  77. {
  78. static constexpr size_t FastSize = SIMDPP_FAST_INT16_SIZE;
  79. template <size_t N>
  80. using SIMDPPType = simdpp::int16<N>;
  81. using FastType = SIMDPPType<FastSize>;
  82. // Depends on instruction set
  83. static constexpr bool Supported = SIMDPP_HAS_INT16_SIMD;
  84. template <typename OutType>
  85. static constexpr bool canConvertTo() {return true;}
  86. template <typename InType>
  87. static SIMDPPType<SIMDTraits<InType>::FastSize> convertFromFastType(typename SIMDTraits<InType>::FastType inReg)
  88. {
  89. simdpp::int16<SIMDTraits<InType>::FastSize> outReg = simdpp::to_int16(inReg);
  90. return outReg;
  91. }
  92. };
  93. template <>
  94. struct SIMDTraits<int32_t>
  95. {
  96. static constexpr size_t FastSize = SIMDPP_FAST_INT32_SIZE;
  97. template <size_t N>
  98. using SIMDPPType = simdpp::int32<N>;
  99. using FastType = SIMDPPType<FastSize>;
  100. // Depends on instruction set
  101. static constexpr bool Supported = SIMDPP_HAS_INT32_SIMD;
  102. template <typename OutType>
  103. static constexpr bool canConvertTo() {return true;}
  104. template <typename InType>
  105. static SIMDPPType<SIMDTraits<InType>::FastSize> convertFromFastType(typename SIMDTraits<InType>::FastType inReg)
  106. {
  107. simdpp::int32<SIMDTraits<InType>::FastSize> outReg = simdpp::to_int32(inReg);
  108. return outReg;
  109. }
  110. };
  111. // Buggy
  112. template <>
  113. constexpr bool SIMDTraits<int32_t>::canConvertTo<char>() {return false;}
  114. // Buggy
  115. template <>
  116. constexpr bool SIMDTraits<int32_t>::canConvertTo<signed char>() {return false;}
  117. // Buggy
  118. template <>
  119. constexpr bool SIMDTraits<int32_t>::canConvertTo<unsigned char>() {return false;}
  120. template <>
  121. struct SIMDTraits<long>
  122. {
  123. static constexpr size_t FastSize = SIMDPP_FAST_INT64_SIZE;
  124. template <size_t N>
  125. using SIMDPPType = simdpp::int64<N>;
  126. using FastType = SIMDPPType<FastSize>;
  127. // Depends on instruction set
  128. static constexpr bool Supported = SIMDPP_HAS_INT64_SIMD;
  129. template <typename OutType>
  130. static constexpr bool canConvertTo() {return false;}
  131. template <typename InType>
  132. static SIMDPPType<SIMDTraits<InType>::FastSize> convertFromFastType(typename SIMDTraits<InType>::FastType inReg)
  133. {
  134. simdpp::int64<SIMDTraits<InType>::FastSize> outReg = simdpp::to_int64(inReg);
  135. return outReg;
  136. }
  137. };
  138. // Depends on instruction set
  139. template <>
  140. constexpr bool SIMDTraits<long>::canConvertTo<float>() {return bool(SIMDPP_HAS_INT64_TO_FLOAT32_CONVERSION);}
  141. // Depends on instruction set
  142. template <>
  143. constexpr bool SIMDTraits<long>::canConvertTo<double>() {return bool(SIMDPP_HAS_INT64_TO_FLOAT64_CONVERSION);}
  144. template <>
  145. struct SIMDTraits<long long>
  146. {
  147. static constexpr size_t FastSize = SIMDPP_FAST_INT64_SIZE;
  148. template <size_t N>
  149. using SIMDPPType = simdpp::int64<N>;
  150. using FastType = SIMDPPType<FastSize>;
  151. // Depends on instruction set
  152. static constexpr bool Supported = SIMDPP_HAS_INT64_SIMD;
  153. template <typename OutType>
  154. static constexpr bool canConvertTo() {return SIMDTraits<long>::canConvertTo<OutType>();}
  155. template <typename InType>
  156. static SIMDPPType<SIMDTraits<InType>::FastSize> convertFromFastType(typename SIMDTraits<InType>::FastType inReg)
  157. {
  158. simdpp::int64<SIMDTraits<InType>::FastSize> outReg = simdpp::to_int64(inReg);
  159. return outReg;
  160. }
  161. };
  162. template <>
  163. struct SIMDTraits<uint8_t>
  164. {
  165. static constexpr size_t FastSize = SIMDPP_FAST_INT8_SIZE;
  166. template <size_t N>
  167. using SIMDPPType = simdpp::uint8<N>;
  168. using FastType = SIMDPPType<FastSize>;
  169. // Depends on instruction set
  170. static constexpr bool Supported = SIMDPP_HAS_INT8_SIMD;
  171. template <typename OutType>
  172. static constexpr bool canConvertTo() {return true;}
  173. template <typename InType>
  174. static SIMDPPType<SIMDTraits<InType>::FastSize> convertFromFastType(typename SIMDTraits<InType>::FastType inReg)
  175. {
  176. simdpp::uint8<SIMDTraits<InType>::FastSize> outReg = simdpp::to_uint8(inReg);
  177. return outReg;
  178. }
  179. };
  180. template <>
  181. struct SIMDTraits<uint16_t>
  182. {
  183. static constexpr size_t FastSize = SIMDPP_FAST_INT16_SIZE;
  184. template <size_t N>
  185. using SIMDPPType = simdpp::uint16<N>;
  186. using FastType = SIMDPPType<FastSize>;
  187. // Depends on instruction set
  188. static constexpr bool Supported = SIMDPP_HAS_INT16_SIMD;
  189. template <typename OutType>
  190. static constexpr bool canConvertTo() {return true;}
  191. template <typename InType>
  192. static SIMDPPType<SIMDTraits<InType>::FastSize> convertFromFastType(typename SIMDTraits<InType>::FastType inReg)
  193. {
  194. simdpp::uint16<SIMDTraits<InType>::FastSize> outReg = simdpp::to_uint16(inReg);
  195. return outReg;
  196. }
  197. };
  198. template <>
  199. struct SIMDTraits<uint32_t>
  200. {
  201. static constexpr size_t FastSize = SIMDPP_FAST_INT32_SIZE;
  202. template <size_t N>
  203. using SIMDPPType = simdpp::uint32<N>;
  204. using FastType = SIMDPPType<FastSize>;
  205. // Depends on instruction set
  206. static constexpr bool Supported = SIMDPP_HAS_INT32_SIMD;
  207. template <typename OutType>
  208. static constexpr bool canConvertTo() {return true;}
  209. template <typename InType>
  210. static SIMDPPType<SIMDTraits<InType>::FastSize> convertFromFastType(typename SIMDTraits<InType>::FastType inReg)
  211. {
  212. simdpp::uint32<SIMDTraits<InType>::FastSize> outReg = simdpp::to_uint32(inReg);
  213. return outReg;
  214. }
  215. };
  216. // Buggy
  217. template <>
  218. constexpr bool SIMDTraits<uint32_t>::canConvertTo<char>() {return false;}
  219. // Buggy
  220. template <>
  221. constexpr bool SIMDTraits<uint32_t>::canConvertTo<signed char>() {return false;}
  222. // Buggy
  223. template <>
  224. constexpr bool SIMDTraits<uint32_t>::canConvertTo<unsigned char>() {return false;}
  225. template <>
  226. struct SIMDTraits<unsigned long>
  227. {
  228. static constexpr size_t FastSize = SIMDPP_FAST_INT64_SIZE;
  229. template <size_t N>
  230. using SIMDPPType = simdpp::uint64<N>;
  231. using FastType = SIMDPPType<FastSize>;
  232. // Depends on instruction set
  233. static constexpr bool Supported = SIMDPP_HAS_INT64_SIMD;
  234. template <typename OutType>
  235. static constexpr bool canConvertTo() {return false;}
  236. template <typename InType>
  237. static SIMDPPType<SIMDTraits<InType>::FastSize> convertFromFastType(typename SIMDTraits<InType>::FastType inReg)
  238. {
  239. simdpp::uint64<SIMDTraits<InType>::FastSize> outReg = simdpp::to_uint64(inReg);
  240. return outReg;
  241. }
  242. };
  243. // Depends on instruction set
  244. template <>
  245. constexpr bool SIMDTraits<unsigned long>::canConvertTo<float>() {return bool(SIMDPP_HAS_INT64_TO_FLOAT32_CONVERSION);}
  246. // Depends on instruction set
  247. template <>
  248. constexpr bool SIMDTraits<unsigned long>::canConvertTo<double>() {return bool(SIMDPP_HAS_INT64_TO_FLOAT64_CONVERSION);}
  249. template <>
  250. struct SIMDTraits<unsigned long long>
  251. {
  252. static constexpr size_t FastSize = SIMDPP_FAST_INT64_SIZE;
  253. template <size_t N>
  254. using SIMDPPType = simdpp::uint64<N>;
  255. using FastType = SIMDPPType<FastSize>;
  256. // Depends on instruction set
  257. static constexpr bool Supported = SIMDPP_HAS_INT64_SIMD;
  258. template <typename OutType>
  259. static constexpr bool canConvertTo() {return SIMDTraits<unsigned long>::canConvertTo<OutType>();}
  260. template <typename InType>
  261. static SIMDPPType<SIMDTraits<InType>::FastSize> convertFromFastType(typename SIMDTraits<InType>::FastType inReg)
  262. {
  263. simdpp::uint64<SIMDTraits<InType>::FastSize> outReg = simdpp::to_uint64(inReg);
  264. return outReg;
  265. }
  266. };
  267. template <>
  268. constexpr bool SIMDTraits<unsigned long long>::canConvertTo<float>() {return bool(SIMDPP_HAS_INT64_TO_FLOAT32_CONVERSION);}
  269. template <>
  270. constexpr bool SIMDTraits<unsigned long long>::canConvertTo<double>() {return bool(SIMDPP_HAS_INT64_TO_FLOAT64_CONVERSION);}
  271. template <>
  272. struct SIMDTraits<float>
  273. {
  274. static constexpr size_t FastSize = SIMDPP_FAST_FLOAT32_SIZE;
  275. template <size_t N>
  276. using SIMDPPType = simdpp::float32<N>;
  277. using FastType = SIMDPPType<FastSize>;
  278. // Depends on instruction set
  279. static constexpr bool Supported = SIMDPP_HAS_FLOAT32_SIMD;
  280. template <typename OutType>
  281. static constexpr bool canConvertTo() {return true;}
  282. template <typename InType>
  283. static SIMDPPType<SIMDTraits<InType>::FastSize> convertFromFastType(typename SIMDTraits<InType>::FastType inReg)
  284. {
  285. simdpp::float32<SIMDTraits<InType>::FastSize> outReg = simdpp::to_float32(inReg);
  286. return outReg;
  287. }
  288. };
  289. template <>
  290. constexpr bool SIMDTraits<float>::canConvertTo<long>() {return bool(SIMDPP_HAS_FLOAT32_TO_INT64_CONVERSION);}
  291. template <>
  292. constexpr bool SIMDTraits<float>::canConvertTo<long long>() {return bool(SIMDPP_HAS_FLOAT32_TO_INT64_CONVERSION);}
  293. template <>
  294. constexpr bool SIMDTraits<float>::canConvertTo<unsigned long>() {return bool(SIMDPP_HAS_FLOAT32_TO_UINT64_CONVERSION);}
  295. template <>
  296. constexpr bool SIMDTraits<float>::canConvertTo<unsigned long long>() {return bool(SIMDPP_HAS_FLOAT32_TO_UINT64_CONVERSION);}
  297. template <>
  298. struct SIMDTraits<double>
  299. {
  300. static constexpr size_t FastSize = SIMDPP_FAST_FLOAT64_SIZE;
  301. template <size_t N>
  302. using SIMDPPType = simdpp::float64<N>;
  303. using FastType = SIMDPPType<FastSize>;
  304. // Depends on instruction set
  305. static constexpr bool Supported = SIMDPP_HAS_FLOAT64_SIMD;
  306. template <typename OutType>
  307. static constexpr bool canConvertTo() {return true;}
  308. template <typename InType>
  309. static SIMDPPType<SIMDTraits<InType>::FastSize> convertFromFastType(typename SIMDTraits<InType>::FastType inReg)
  310. {
  311. simdpp::float64<SIMDTraits<InType>::FastSize> outReg = simdpp::to_float64(inReg);
  312. return outReg;
  313. }
  314. };
  315. template <>
  316. constexpr bool SIMDTraits<double>::canConvertTo<long>() {return bool(SIMDPP_HAS_FLOAT64_TO_INT64_CONVERSION);}
  317. template <>
  318. constexpr bool SIMDTraits<double>::canConvertTo<long long>() {return bool(SIMDPP_HAS_FLOAT64_TO_INT64_CONVERSION);}
  319. template <>
  320. constexpr bool SIMDTraits<double>::canConvertTo<std::uint32_t>() {return bool(SIMDPP_HAS_FLOAT64_TO_UINT32_CONVERSION);}
  321. template <>
  322. constexpr bool SIMDTraits<double>::canConvertTo<unsigned long>() {return bool(SIMDPP_HAS_FLOAT64_TO_UINT64_CONVERSION);}
  323. template <>
  324. constexpr bool SIMDTraits<double>::canConvertTo<unsigned long long>() {return bool(SIMDPP_HAS_FLOAT64_TO_UINT64_CONVERSION);}
  325. template <typename InType, typename OutType>
  326. struct BothComplex: std::integral_constant<bool,
  327. Pothos::Util::is_complex<InType>::value &&
  328. Pothos::Util::is_complex<OutType>::value
  329. > {};
  330. template <typename InType, typename OutType>
  331. struct NeitherComplex: std::integral_constant<bool,
  332. !Pothos::Util::is_complex<InType>::value &&
  333. !Pothos::Util::is_complex<OutType>::value
  334. > {};
  335. // See: libsimdpp/simdpp/capabilities.h
  336. template <typename InType, typename OutType>
  337. struct CanInstructionSetConvert: std::integral_constant<bool,
  338. NeitherComplex<InType, OutType>::value &&
  339. !std::is_same<InType, OutType>::value &&
  340. // For some reason, double -> integral conversions don't compile with some
  341. // architectures.
  342. #if SIMDPP_ARCH_PP_NS_USE_POPCNT_INSN
  343. !(std::is_same<double, InType>::value && std::is_integral<OutType>::value) &&
  344. #endif
  345. !(std::is_floating_point<InType>::value && std::is_integral<OutType>::value) &&
  346. SIMDTraits<InType>::Supported && SIMDTraits<OutType>::Supported &&
  347. SIMDTraits<InType>::template canConvertTo<OutType>()> {};
  348. template <typename InType, typename OutType, typename Ret>
  349. using EnableIfInstructionSetCanConvert = typename std::enable_if<
  350. CanInstructionSetConvert<InType, OutType>::value,
  351. Ret
  352. >::type;
  353. template <typename InType, typename OutType, typename Ret>
  354. using EnableIfNonComplexTypesMatch = typename std::enable_if<
  355. std::is_same<InType, OutType>::value &&
  356. !Pothos::Util::is_complex<InType>::value,
  357. Ret
  358. >::type;
  359. template <typename InType, typename OutType, typename Ret>
  360. using EnableIfNeitherComplex = typename std::enable_if<
  361. CanInstructionSetConvert<InType, OutType>::value && NeitherComplex<InType, OutType>::value,
  362. Ret
  363. >::type;
  364. template <typename InType, typename OutType, typename Ret>
  365. using EnableIfBothComplex = typename std::enable_if<BothComplex<InType, OutType>::value, Ret>::type;
  366. template <typename InType, typename OutType, typename Ret>
  367. using EnableIfConversionUnsupported = typename std::enable_if<
  368. !CanInstructionSetConvert<InType, OutType>::value && NeitherComplex<InType, OutType>::value && !std::is_same<InType, OutType>::value,
  369. Ret
  370. >::type;
  371. template <typename InType, typename OutType>
  372. static EnableIfInstructionSetCanConvert<InType, OutType, void>
  373. simdConvertBuffer(
  374. const InType* in,
  375. OutType* out,
  376. size_t bufferLen)
  377. {
  378. static constexpr size_t FrameSize = SIMDTraits<InType>::FastSize;
  379. using SIMDPPTypeIn = typename SIMDTraits<InType>::FastType;
  380. const auto numFrames = bufferLen / FrameSize;
  381. const InType* inPtr = in;
  382. OutType* outPtr = out;
  383. for(size_t frameIndex = 0; frameIndex < numFrames; ++frameIndex)
  384. {
  385. SIMDPPTypeIn inReg = simdpp::load_u(inPtr);
  386. auto outReg = SIMDTraits<OutType>::template convertFromFastType<InType>(inReg);
  387. simdpp::store_u(outPtr, outReg);
  388. inPtr += FrameSize;
  389. outPtr += FrameSize;
  390. }
  391. // Perform remaining conversions manually.
  392. for(size_t i = (FrameSize * numFrames); i < bufferLen; ++i)
  393. {
  394. out[i] = static_cast<OutType>(in[i]);
  395. }
  396. }
  397. template <typename InType, typename OutType>
  398. static EnableIfNonComplexTypesMatch<InType, OutType, void>
  399. simdConvertBuffer(
  400. const InType* in,
  401. OutType* out,
  402. size_t bufferLen)
  403. {
  404. std::memcpy(out, in, (bufferLen*sizeof(InType)));
  405. }
  406. template <typename InType, typename OutType>
  407. static EnableIfConversionUnsupported<InType, OutType, void>
  408. simdConvertBuffer(
  409. const InType* in,
  410. OutType* out,
  411. size_t bufferLen)
  412. {
  413. static_assert(NeitherComplex<InType, OutType>::value, "Unsupported overload called with complex types");
  414. for(size_t i = 0; i < bufferLen; ++i)
  415. {
  416. out[i] = static_cast<OutType>(in[i]);
  417. }
  418. }
  419. template <typename InType, typename OutType>
  420. static EnableIfBothComplex<InType, OutType, void>
  421. simdConvertBuffer(
  422. const InType* in,
  423. OutType* out,
  424. size_t bufferLen)
  425. {
  426. using ScalarInType = typename InType::value_type;
  427. using ScalarOutType = typename OutType::value_type;
  428. static_assert(NeitherComplex<ScalarInType, ScalarOutType>::value, "Complex overload called with double-complex types");
  429. simdConvertBuffer<ScalarInType, ScalarOutType>(
  430. (const ScalarInType*)in,
  431. (ScalarOutType*)out,
  432. (bufferLen*2));
  433. }
  434. }
  435. template <typename InType, typename OutType>
  436. void simdConvertBuffer(const void* in, void* out, size_t bufferLen)
  437. {
  438. detail::simdConvertBuffer<InType, OutType>(
  439. (const InType*) in,
  440. (OutType*)out,
  441. bufferLen);
  442. }
  443. }
  444. // This generates the underlying code that queries the runnable instruction
  445. // sets and chooses the most optimal to use. This code is only generated in
  446. // the first of the files generated by SIMDPP's CMake module.
  447. SIMDPP_MAKE_DISPATCHER(
  448. (template<typename InType, typename OutType>)
  449. (<InType, OutType>)
  450. (void)(simdConvertBuffer)
  451. ((const void*) in, (void*) out, (size_t) bufferLen))
  452. // Separate dispatcher macros because it there are only
  453. // underlying overloads for so many template specializations
  454. // at once.
  455. #define INSTANTIATE_DISPATCHERS(T) \
  456. SIMDPP_INSTANTIATE_DISPATCHER( \
  457. (template void simdConvertBuffer<T, char>(const void* in, void* out, size_t bufferLen)), \
  458. (template void simdConvertBuffer<T, std::int8_t>(const void* in, void* out, size_t bufferLen)), \
  459. (template void simdConvertBuffer<T, std::int16_t>(const void* in, void* out, size_t bufferLen)), \
  460. (template void simdConvertBuffer<T, std::int32_t>(const void* in, void* out, size_t bufferLen)), \
  461. (template void simdConvertBuffer<T, long>(const void* in, void* out, size_t bufferLen)), \
  462. (template void simdConvertBuffer<T, long long>(const void* in, void* out, size_t bufferLen)), \
  463. (template void simdConvertBuffer<T, std::uint8_t>(const void* in, void* out, size_t bufferLen)), \
  464. (template void simdConvertBuffer<T, std::uint16_t>(const void* in, void* out, size_t bufferLen)), \
  465. (template void simdConvertBuffer<T, std::uint32_t>(const void* in, void* out, size_t bufferLen)), \
  466. (template void simdConvertBuffer<T, unsigned long>(const void* in, void* out, size_t bufferLen)), \
  467. (template void simdConvertBuffer<T, unsigned long long>(const void* in, void* out, size_t bufferLen)), \
  468. (template void simdConvertBuffer<T, float>(const void* in, void* out, size_t bufferLen)), \
  469. (template void simdConvertBuffer<T, double>(const void* in, void* out, size_t bufferLen)) \
  470. ) \
  471. SIMDPP_INSTANTIATE_DISPATCHER( \
  472. (template void simdConvertBuffer<std::complex<T>, std::complex<char>>(const void* in, void* out, size_t bufferLen)), \
  473. (template void simdConvertBuffer<std::complex<T>, std::complex<std::int8_t>>(const void* in, void* out, size_t bufferLen)), \
  474. (template void simdConvertBuffer<std::complex<T>, std::complex<std::int16_t>>(const void* in, void* out, size_t bufferLen)), \
  475. (template void simdConvertBuffer<std::complex<T>, std::complex<std::int32_t>>(const void* in, void* out, size_t bufferLen)), \
  476. (template void simdConvertBuffer<std::complex<T>, std::complex<long>>(const void* in, void* out, size_t bufferLen)), \
  477. (template void simdConvertBuffer<std::complex<T>, std::complex<long long>>(const void* in, void* out, size_t bufferLen)), \
  478. (template void simdConvertBuffer<std::complex<T>, std::complex<std::uint8_t>>(const void* in, void* out, size_t bufferLen)), \
  479. (template void simdConvertBuffer<std::complex<T>, std::complex<std::uint16_t>>(const void* in, void* out, size_t bufferLen)), \
  480. (template void simdConvertBuffer<std::complex<T>, std::complex<std::uint32_t>>(const void* in, void* out, size_t bufferLen)), \
  481. (template void simdConvertBuffer<std::complex<T>, std::complex<unsigned long>>(const void* in, void* out, size_t bufferLen)), \
  482. (template void simdConvertBuffer<std::complex<T>, std::complex<unsigned long long>>(const void* in, void* out, size_t bufferLen)), \
  483. (template void simdConvertBuffer<std::complex<T>, std::complex<float>>(const void* in, void* out, size_t bufferLen)), \
  484. (template void simdConvertBuffer<std::complex<T>, std::complex<double>>(const void* in, void* out, size_t bufferLen)) \
  485. )
  486. INSTANTIATE_DISPATCHERS(char)
  487. INSTANTIATE_DISPATCHERS(std::int8_t)
  488. INSTANTIATE_DISPATCHERS(std::int16_t)
  489. INSTANTIATE_DISPATCHERS(std::int32_t)
  490. INSTANTIATE_DISPATCHERS(long)
  491. INSTANTIATE_DISPATCHERS(long long)
  492. INSTANTIATE_DISPATCHERS(std::uint8_t)
  493. INSTANTIATE_DISPATCHERS(std::uint16_t)
  494. INSTANTIATE_DISPATCHERS(std::uint32_t)
  495. INSTANTIATE_DISPATCHERS(unsigned long)
  496. INSTANTIATE_DISPATCHERS(unsigned long long)
  497. INSTANTIATE_DISPATCHERS(float)
  498. INSTANTIATE_DISPATCHERS(double)