intrin_wrapper.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. #ifndef _SCTL_INTRIN_WRAPPER_HPP_
  2. #define _SCTL_INTRIN_WRAPPER_HPP_
  3. #include SCTL_INCLUDE(math_utils.hpp)
  4. #include SCTL_INCLUDE(common.hpp)
  5. #include <cstdint>
  6. #ifdef __SSE__
  7. #include <xmmintrin.h>
  8. #endif
  9. #ifdef __SSE2__
  10. #include <emmintrin.h>
  11. #endif
  12. #ifdef __SSE3__
  13. #include <pmmintrin.h>
  14. #endif
  15. #ifdef __AVX__
  16. #include <immintrin.h>
  17. #endif
  18. #if defined(__MIC__)
  19. #include <immintrin.h>
  20. #endif
  21. namespace SCTL_NAMESPACE {
  22. template <class T> inline T zero_intrin() { return (T)0; }
  23. template <class T, class Real> inline T set_intrin(const Real& a) { return a; }
  24. template <class T, class Real> inline T load_intrin(Real const* a) { return a[0]; }
  25. template <class T, class Real> inline T bcast_intrin(Real const* a) { return a[0]; }
  26. template <class T, class Real> inline void store_intrin(Real* a, const T& b) { a[0] = b; }
  27. template <class T> inline T mul_intrin(const T& a, const T& b) { return a * b; }
  28. template <class T> inline T add_intrin(const T& a, const T& b) { return a + b; }
  29. template <class T> inline T sub_intrin(const T& a, const T& b) { return a - b; }
  30. template <class T> inline T cmplt_intrin(const T& a, const T& b) {
  31. T r = 0;
  32. uint8_t* r_ = reinterpret_cast<uint8_t*>(&r);
  33. if (a < b)
  34. for (int i = 0; i < sizeof(T); i++) r_[i] = ~(uint8_t)0;
  35. return r;
  36. }
  37. template <class T> inline T and_intrin(const T& a, const T& b) {
  38. T r = 0;
  39. const uint8_t* a_ = reinterpret_cast<const uint8_t*>(&a);
  40. const uint8_t* b_ = reinterpret_cast<const uint8_t*>(&b);
  41. uint8_t* r_ = reinterpret_cast<uint8_t*>(&r);
  42. for (int i = 0; i < sizeof(T); i++) r_[i] = a_[i] & b_[i];
  43. return r;
  44. }
  45. template <class T> inline T rsqrt_approx_intrin(const T& r2) {
  46. if (r2 != 0) return 1.0 / sqrt<T>(r2);
  47. return 0;
  48. }
  49. template <class T, class Real> inline void rsqrt_newton_intrin(T& rinv, const T& r2, const Real& nwtn_const) { rinv = rinv * (nwtn_const - r2 * rinv * rinv); }
  50. template <class T> inline T rsqrt_single_intrin(const T& r2) {
  51. if (r2 != 0) return 1.0 / sqrt<T>(r2);
  52. return 0;
  53. }
  54. template <class T> inline T max_intrin(const T& a, const T& b) {
  55. if (a > b)
  56. return a;
  57. else
  58. return b;
  59. }
  60. template <class T> inline T min_intrin(const T& a, const T& b) {
  61. if (a > b)
  62. return b;
  63. else
  64. return a;
  65. }
  66. template <class T> inline T sin_intrin(const T& t) { return sin<T>(t); }
  67. template <class T> inline T cos_intrin(const T& t) { return cos<T>(t); }
  68. #ifdef __SSE3__
  69. template <> inline __m128 zero_intrin() { return _mm_setzero_ps(); }
  70. template <> inline __m128d zero_intrin() { return _mm_setzero_pd(); }
  71. template <> inline __m128 set_intrin(const float& a) { return _mm_set_ps1(a); }
  72. template <> inline __m128d set_intrin(const double& a) { return _mm_set_pd1(a); }
  73. template <> inline __m128 load_intrin(float const* a) { return _mm_load_ps(a); }
  74. template <> inline __m128d load_intrin(double const* a) { return _mm_load_pd(a); }
  75. template <> inline __m128 bcast_intrin(float const* a) { return _mm_set_ps1(a[0]); }
  76. template <> inline __m128d bcast_intrin(double const* a) { return _mm_load_pd1(a); }
  77. template <> inline void store_intrin(float* a, const __m128& b) { return _mm_store_ps(a, b); }
  78. template <> inline void store_intrin(double* a, const __m128d& b) { return _mm_store_pd(a, b); }
  79. template <> inline __m128 mul_intrin(const __m128& a, const __m128& b) { return _mm_mul_ps(a, b); }
  80. template <> inline __m128d mul_intrin(const __m128d& a, const __m128d& b) { return _mm_mul_pd(a, b); }
  81. template <> inline __m128 add_intrin(const __m128& a, const __m128& b) { return _mm_add_ps(a, b); }
  82. template <> inline __m128d add_intrin(const __m128d& a, const __m128d& b) { return _mm_add_pd(a, b); }
  83. template <> inline __m128 sub_intrin(const __m128& a, const __m128& b) { return _mm_sub_ps(a, b); }
  84. template <> inline __m128d sub_intrin(const __m128d& a, const __m128d& b) { return _mm_sub_pd(a, b); }
  85. template <> inline __m128 cmplt_intrin(const __m128& a, const __m128& b) { return _mm_cmplt_ps(a, b); }
  86. template <> inline __m128d cmplt_intrin(const __m128d& a, const __m128d& b) { return _mm_cmplt_pd(a, b); }
  87. template <> inline __m128 and_intrin(const __m128& a, const __m128& b) { return _mm_and_ps(a, b); }
  88. template <> inline __m128d and_intrin(const __m128d& a, const __m128d& b) { return _mm_and_pd(a, b); }
  89. template <> inline __m128 rsqrt_approx_intrin(const __m128& r2) {
  90. #define VEC_INTRIN __m128
  91. #define RSQRT_INTRIN(a) _mm_rsqrt_ps(a)
  92. #define CMPEQ_INTRIN(a, b) _mm_cmpeq_ps(a, b)
  93. #define ANDNOT_INTRIN(a, b) _mm_andnot_ps(a, b)
  94. // Approx inverse square root which returns zero for r2=0
  95. return ANDNOT_INTRIN(CMPEQ_INTRIN(r2, zero_intrin<VEC_INTRIN>()), RSQRT_INTRIN(r2));
  96. #undef VEC_INTRIN
  97. #undef RSQRT_INTRIN
  98. #undef CMPEQ_INTRIN
  99. #undef ANDNOT_INTRIN
  100. }
  101. template <> inline __m128d rsqrt_approx_intrin(const __m128d& r2) {
  102. #define PD2PS(a) _mm_cvtpd_ps(a)
  103. #define PS2PD(a) _mm_cvtps_pd(a)
  104. return PS2PD(rsqrt_approx_intrin(PD2PS(r2)));
  105. #undef PD2PS
  106. #undef PS2PD
  107. }
  108. template <> inline void rsqrt_newton_intrin(__m128& rinv, const __m128& r2, const float& nwtn_const) {
  109. #define VEC_INTRIN __m128
  110. // Newton iteration: rinv = 0.5 rinv_approx ( 3 - r2 rinv_approx^2 )
  111. // We do not compute the product with 0.5 and this needs to be adjusted later
  112. rinv = mul_intrin(rinv, sub_intrin(set_intrin<VEC_INTRIN>(nwtn_const), mul_intrin(r2, mul_intrin(rinv, rinv))));
  113. #undef VEC_INTRIN
  114. }
  115. template <> inline void rsqrt_newton_intrin(__m128d& rinv, const __m128d& r2, const double& nwtn_const) {
  116. #define VEC_INTRIN __m128d
  117. // Newton iteration: rinv = 0.5 rinv_approx ( 3 - r2 rinv_approx^2 )
  118. // We do not compute the product with 0.5 and this needs to be adjusted later
  119. rinv = mul_intrin(rinv, sub_intrin(set_intrin<VEC_INTRIN>(nwtn_const), mul_intrin(r2, mul_intrin(rinv, rinv))));
  120. #undef VEC_INTRIN
  121. }
  122. template <> inline __m128 rsqrt_single_intrin(const __m128& r2) {
  123. #define VEC_INTRIN __m128
  124. VEC_INTRIN rinv = rsqrt_approx_intrin(r2);
  125. rsqrt_newton_intrin(rinv, r2, (float)3.0);
  126. return rinv;
  127. #undef VEC_INTRIN
  128. }
  129. template <> inline __m128d rsqrt_single_intrin(const __m128d& r2) {
  130. #define PD2PS(a) _mm_cvtpd_ps(a)
  131. #define PS2PD(a) _mm_cvtps_pd(a)
  132. return PS2PD(rsqrt_single_intrin(PD2PS(r2)));
  133. #undef PD2PS
  134. #undef PS2PD
  135. }
  136. template <> inline __m128 max_intrin(const __m128& a, const __m128& b) { return _mm_max_ps(a, b); }
  137. template <> inline __m128d max_intrin(const __m128d& a, const __m128d& b) { return _mm_max_pd(a, b); }
  138. template <> inline __m128 min_intrin(const __m128& a, const __m128& b) { return _mm_min_ps(a, b); }
  139. template <> inline __m128d min_intrin(const __m128d& a, const __m128d& b) { return _mm_min_pd(a, b); }
  140. #ifdef SCTL_HAVE_INTEL_SVML
  141. template <> inline __m128 sin_intrin(const __m128& t) { return _mm_sin_ps(t); }
  142. template <> inline __m128 cos_intrin(const __m128& t) { return _mm_cos_ps(t); }
  143. template <> inline __m128d sin_intrin(const __m128d& t) { return _mm_sin_pd(t); }
  144. template <> inline __m128d cos_intrin(const __m128d& t) { return _mm_cos_pd(t); }
  145. #else
  146. template <> inline __m128 sin_intrin(const __m128& t_) {
  147. union {
  148. float e[4];
  149. __m128 d;
  150. } t;
  151. store_intrin(t.e, t_);
  152. return _mm_set_ps(sin<float>(t.e[3]), sin<float>(t.e[2]), sin<float>(t.e[1]), sin<float>(t.e[0]));
  153. }
  154. template <> inline __m128 cos_intrin(const __m128& t_) {
  155. union {
  156. float e[4];
  157. __m128 d;
  158. } t;
  159. store_intrin(t.e, t_);
  160. return _mm_set_ps(cos<float>(t.e[3]), cos<float>(t.e[2]), cos<float>(t.e[1]), cos<float>(t.e[0]));
  161. }
  162. template <> inline __m128d sin_intrin(const __m128d& t_) {
  163. union {
  164. double e[2];
  165. __m128d d;
  166. } t;
  167. store_intrin(t.e, t_);
  168. return _mm_set_pd(sin<double>(t.e[1]), sin<double>(t.e[0]));
  169. }
  170. template <> inline __m128d cos_intrin(const __m128d& t_) {
  171. union {
  172. double e[2];
  173. __m128d d;
  174. } t;
  175. store_intrin(t.e, t_);
  176. return _mm_set_pd(cos<double>(t.e[1]), cos<double>(t.e[0]));
  177. }
  178. #endif
  179. #endif
  180. #ifdef __AVX__
  181. template <> inline __m256 zero_intrin() { return _mm256_setzero_ps(); }
  182. template <> inline __m256d zero_intrin() { return _mm256_setzero_pd(); }
  183. template <> inline __m256 set_intrin(const float& a) { return _mm256_set_ps(a, a, a, a, a, a, a, a); }
  184. template <> inline __m256d set_intrin(const double& a) { return _mm256_set_pd(a, a, a, a); }
  185. template <> inline __m256 load_intrin(float const* a) { return _mm256_load_ps(a); }
  186. template <> inline __m256d load_intrin(double const* a) { return _mm256_load_pd(a); }
  187. template <> inline __m256 bcast_intrin(float const* a) { return _mm256_broadcast_ss(a); }
  188. template <> inline __m256d bcast_intrin(double const* a) { return _mm256_broadcast_sd(a); }
  189. template <> inline void store_intrin(float* a, const __m256& b) { return _mm256_store_ps(a, b); }
  190. template <> inline void store_intrin(double* a, const __m256d& b) { return _mm256_store_pd(a, b); }
  191. template <> inline __m256 mul_intrin(const __m256& a, const __m256& b) { return _mm256_mul_ps(a, b); }
  192. template <> inline __m256d mul_intrin(const __m256d& a, const __m256d& b) { return _mm256_mul_pd(a, b); }
  193. template <> inline __m256 add_intrin(const __m256& a, const __m256& b) { return _mm256_add_ps(a, b); }
  194. template <> inline __m256d add_intrin(const __m256d& a, const __m256d& b) { return _mm256_add_pd(a, b); }
  195. template <> inline __m256 sub_intrin(const __m256& a, const __m256& b) { return _mm256_sub_ps(a, b); }
  196. template <> inline __m256d sub_intrin(const __m256d& a, const __m256d& b) { return _mm256_sub_pd(a, b); }
  197. template <> inline __m256 cmplt_intrin(const __m256& a, const __m256& b) { return _mm256_cmp_ps(a, b, _CMP_LT_OS); }
  198. template <> inline __m256d cmplt_intrin(const __m256d& a, const __m256d& b) { return _mm256_cmp_pd(a, b, _CMP_LT_OS); }
  199. template <> inline __m256 and_intrin(const __m256& a, const __m256& b) { return _mm256_and_ps(a, b); }
  200. template <> inline __m256d and_intrin(const __m256d& a, const __m256d& b) { return _mm256_and_pd(a, b); }
  201. template <> inline __m256 rsqrt_approx_intrin(const __m256& r2) {
  202. #define VEC_INTRIN __m256
  203. #define RSQRT_INTRIN(a) _mm256_rsqrt_ps(a)
  204. #define CMPEQ_INTRIN(a, b) _mm256_cmp_ps(a, b, _CMP_EQ_OS)
  205. #define ANDNOT_INTRIN(a, b) _mm256_andnot_ps(a, b)
  206. // Approx inverse square root which returns zero for r2=0
  207. return ANDNOT_INTRIN(CMPEQ_INTRIN(r2, zero_intrin<VEC_INTRIN>()), RSQRT_INTRIN(r2));
  208. #undef VEC_INTRIN
  209. #undef RSQRT_INTRIN
  210. #undef CMPEQ_INTRIN
  211. #undef ANDNOT_INTRIN
  212. }
  213. template <> inline __m256d rsqrt_approx_intrin(const __m256d& r2) {
  214. #define PD2PS(a) _mm256_cvtpd_ps(a)
  215. #define PS2PD(a) _mm256_cvtps_pd(a)
  216. return PS2PD(rsqrt_approx_intrin(PD2PS(r2)));
  217. #undef PD2PS
  218. #undef PS2PD
  219. }
  220. template <> inline void rsqrt_newton_intrin(__m256& rinv, const __m256& r2, const float& nwtn_const) {
  221. #define VEC_INTRIN __m256
  222. // Newton iteration: rinv = 0.5 rinv_approx ( 3 - r2 rinv_approx^2 )
  223. // We do not compute the product with 0.5 and this needs to be adjusted later
  224. rinv = mul_intrin(rinv, sub_intrin(set_intrin<VEC_INTRIN>(nwtn_const), mul_intrin(r2, mul_intrin(rinv, rinv))));
  225. #undef VEC_INTRIN
  226. }
  227. template <> inline void rsqrt_newton_intrin(__m256d& rinv, const __m256d& r2, const double& nwtn_const) {
  228. #define VEC_INTRIN __m256d
  229. // Newton iteration: rinv = 0.5 rinv_approx ( 3 - r2 rinv_approx^2 )
  230. // We do not compute the product with 0.5 and this needs to be adjusted later
  231. rinv = mul_intrin(rinv, sub_intrin(set_intrin<VEC_INTRIN>(nwtn_const), mul_intrin(r2, mul_intrin(rinv, rinv))));
  232. #undef VEC_INTRIN
  233. }
  234. template <> inline __m256 rsqrt_single_intrin(const __m256& r2) {
  235. #define VEC_INTRIN __m256
  236. VEC_INTRIN rinv = rsqrt_approx_intrin(r2);
  237. rsqrt_newton_intrin(rinv, r2, (float)3.0);
  238. return rinv;
  239. #undef VEC_INTRIN
  240. }
  241. template <> inline __m256d rsqrt_single_intrin(const __m256d& r2) {
  242. #define PD2PS(a) _mm256_cvtpd_ps(a)
  243. #define PS2PD(a) _mm256_cvtps_pd(a)
  244. return PS2PD(rsqrt_single_intrin(PD2PS(r2)));
  245. #undef PD2PS
  246. #undef PS2PD
  247. }
  248. template <> inline __m256 max_intrin(const __m256& a, const __m256& b) { return _mm256_max_ps(a, b); }
  249. template <> inline __m256d max_intrin(const __m256d& a, const __m256d& b) { return _mm256_max_pd(a, b); }
  250. template <> inline __m256 min_intrin(const __m256& a, const __m256& b) { return _mm256_min_ps(a, b); }
  251. template <> inline __m256d min_intrin(const __m256d& a, const __m256d& b) { return _mm256_min_pd(a, b); }
  252. #ifdef SCTL_HAVE_INTEL_SVML
  253. template <> inline __m256 sin_intrin(const __m256& t) { return _mm256_sin_ps(t); }
  254. template <> inline __m256 cos_intrin(const __m256& t) { return _mm256_cos_ps(t); }
  255. template <> inline __m256d sin_intrin(const __m256d& t) { return _mm256_sin_pd(t); }
  256. template <> inline __m256d cos_intrin(const __m256d& t) { return _mm256_cos_pd(t); }
  257. #else
  258. template <> inline __m256 sin_intrin(const __m256& t_) {
  259. union {
  260. float e[8];
  261. __m256 d;
  262. } t;
  263. store_intrin(t.e, t_); // t.d=t_;
  264. return _mm256_set_ps(sin<float>(t.e[7]), sin<float>(t.e[6]), sin<float>(t.e[5]), sin<float>(t.e[4]), sin<float>(t.e[3]), sin<float>(t.e[2]), sin<float>(t.e[1]), sin<float>(t.e[0]));
  265. }
  266. template <> inline __m256 cos_intrin(const __m256& t_) {
  267. union {
  268. float e[8];
  269. __m256 d;
  270. } t;
  271. store_intrin(t.e, t_); // t.d=t_;
  272. return _mm256_set_ps(cos<float>(t.e[7]), cos<float>(t.e[6]), cos<float>(t.e[5]), cos<float>(t.e[4]), cos<float>(t.e[3]), cos<float>(t.e[2]), cos<float>(t.e[1]), cos<float>(t.e[0]));
  273. }
  274. template <> inline __m256d sin_intrin(const __m256d& t_) {
  275. union {
  276. double e[4];
  277. __m256d d;
  278. } t;
  279. store_intrin(t.e, t_); // t.d=t_;
  280. return _mm256_set_pd(sin<double>(t.e[3]), sin<double>(t.e[2]), sin<double>(t.e[1]), sin<double>(t.e[0]));
  281. }
  282. template <> inline __m256d cos_intrin(const __m256d& t_) {
  283. union {
  284. double e[4];
  285. __m256d d;
  286. } t;
  287. store_intrin(t.e, t_); // t.d=t_;
  288. return _mm256_set_pd(cos<double>(t.e[3]), cos<double>(t.e[2]), cos<double>(t.e[1]), cos<double>(t.e[0]));
  289. }
  290. #endif
  291. #endif
  292. template <class VEC, class Real> inline VEC rsqrt_intrin0(VEC r2) {
  293. #define NWTN0 0
  294. #define NWTN1 0
  295. #define NWTN2 0
  296. #define NWTN3 0
  297. // Real scal=1; Real const_nwtn0=3*scal*scal;
  298. // scal=(NWTN0?2*scal*scal*scal:scal); Real const_nwtn1=3*scal*scal;
  299. // scal=(NWTN1?2*scal*scal*scal:scal); Real const_nwtn2=3*scal*scal;
  300. // scal=(NWTN2?2*scal*scal*scal:scal); Real const_nwtn3=3*scal*scal;
  301. VEC rinv;
  302. #if NWTN0
  303. rinv = rsqrt_single_intrin(r2);
  304. #else
  305. rinv = rsqrt_approx_intrin(r2);
  306. #endif
  307. #if NWTN1
  308. rsqrt_newton_intrin(rinv, r2, const_nwtn1);
  309. #endif
  310. #if NWTN2
  311. rsqrt_newton_intrin(rinv, r2, const_nwtn2);
  312. #endif
  313. #if NWTN3
  314. rsqrt_newton_intrin(rinv, r2, const_nwtn3);
  315. #endif
  316. return rinv;
  317. #undef NWTN0
  318. #undef NWTN1
  319. #undef NWTN2
  320. #undef NWTN3
  321. }
  322. template <class VEC, class Real> inline VEC rsqrt_intrin1(VEC r2) {
  323. #define NWTN0 0
  324. #define NWTN1 1
  325. #define NWTN2 0
  326. #define NWTN3 0
  327. Real scal = 1; // Real const_nwtn0=3*scal*scal;
  328. scal = (NWTN0 ? 2 * scal * scal * scal : scal);
  329. Real const_nwtn1 = 3 * scal * scal;
  330. // scal=(NWTN1?2*scal*scal*scal:scal); Real const_nwtn2=3*scal*scal;
  331. // scal=(NWTN2?2*scal*scal*scal:scal); Real const_nwtn3=3*scal*scal;
  332. VEC rinv;
  333. #if NWTN0
  334. rinv = rsqrt_single_intrin(r2);
  335. #else
  336. rinv = rsqrt_approx_intrin(r2);
  337. #endif
  338. #if NWTN1
  339. rsqrt_newton_intrin(rinv, r2, const_nwtn1);
  340. #endif
  341. #if NWTN2
  342. rsqrt_newton_intrin(rinv, r2, const_nwtn2);
  343. #endif
  344. #if NWTN3
  345. rsqrt_newton_intrin(rinv, r2, const_nwtn3);
  346. #endif
  347. return rinv;
  348. #undef NWTN0
  349. #undef NWTN1
  350. #undef NWTN2
  351. #undef NWTN3
  352. }
  353. template <class VEC, class Real> inline VEC rsqrt_intrin2(VEC r2) {
  354. #define NWTN0 0
  355. #define NWTN1 1
  356. #define NWTN2 1
  357. #define NWTN3 0
  358. Real scal = 1; // Real const_nwtn0=3*scal*scal;
  359. scal = (NWTN0 ? 2 * scal * scal * scal : scal);
  360. Real const_nwtn1 = 3 * scal * scal;
  361. scal = (NWTN1 ? 2 * scal * scal * scal : scal);
  362. Real const_nwtn2 = 3 * scal * scal;
  363. // scal=(NWTN2?2*scal*scal*scal:scal); Real const_nwtn3=3*scal*scal;
  364. VEC rinv;
  365. #if NWTN0
  366. rinv = rsqrt_single_intrin(r2);
  367. #else
  368. rinv = rsqrt_approx_intrin(r2);
  369. #endif
  370. #if NWTN1
  371. rsqrt_newton_intrin(rinv, r2, const_nwtn1);
  372. #endif
  373. #if NWTN2
  374. rsqrt_newton_intrin(rinv, r2, const_nwtn2);
  375. #endif
  376. #if NWTN3
  377. rsqrt_newton_intrin(rinv, r2, const_nwtn3);
  378. #endif
  379. return rinv;
  380. #undef NWTN0
  381. #undef NWTN1
  382. #undef NWTN2
  383. #undef NWTN3
  384. }
  385. template <class VEC, class Real> inline VEC rsqrt_intrin3(VEC r2) {
  386. #define NWTN0 0
  387. #define NWTN1 1
  388. #define NWTN2 1
  389. #define NWTN3 1
  390. Real scal = 1; // Real const_nwtn0=3*scal*scal;
  391. scal = (NWTN0 ? 2 * scal * scal * scal : scal);
  392. Real const_nwtn1 = 3 * scal * scal;
  393. scal = (NWTN1 ? 2 * scal * scal * scal : scal);
  394. Real const_nwtn2 = 3 * scal * scal;
  395. scal = (NWTN2 ? 2 * scal * scal * scal : scal);
  396. Real const_nwtn3 = 3 * scal * scal;
  397. VEC rinv;
  398. #if NWTN0
  399. rinv = rsqrt_single_intrin(r2);
  400. #else
  401. rinv = rsqrt_approx_intrin(r2);
  402. #endif
  403. #if NWTN1
  404. rsqrt_newton_intrin(rinv, r2, const_nwtn1);
  405. #endif
  406. #if NWTN2
  407. rsqrt_newton_intrin(rinv, r2, const_nwtn2);
  408. #endif
  409. #if NWTN3
  410. rsqrt_newton_intrin(rinv, r2, const_nwtn3);
  411. #endif
  412. return rinv;
  413. #undef NWTN0
  414. #undef NWTN1
  415. #undef NWTN2
  416. #undef NWTN3
  417. }
  418. }
  419. #endif //_SCTL_INTRIN_WRAPPER_HPP_