You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

471 lines
15KB

  1. /* Modified version of http://gruntthepeon.free.fr/ssemath/ for VCV Rack.
  2. The following changes were made.
  3. - Remove typedefs for __m128 to avoid type pollution, and because they're not that ugly.
  4. - Make all functions inline since this is a header file.
  5. - Remove non-SSE2 code, since Rack assumes SSE2 CPUs.
  6. - Move `const static` variables to function variables for clarity. See https://stackoverflow.com/a/52139901/272642 for explanation of why the performance is not worse.
  7. - Change header file to <pmmintrin.h> since we're using SSE2 intrinsics.
  8. - Prefix functions with `sse_mathfun_`.
  9. - Add floor, ceil, fmod.
  10. This derived source file is released under the zlib license.
  11. */
  12. /* SIMD (SSE1+MMX or SSE2) implementation of sin, cos, exp and log
  13. Inspired by Intel Approximate Math library, and based on the
  14. corresponding algorithms of the cephes math library
  15. The default is to use the SSE1 version. If you define USE_SSE2 the
  16. the SSE2 intrinsics will be used in place of the MMX intrinsics. Do
  17. not expect any significant performance improvement with SSE2.
  18. */
  19. /* Copyright (C) 2007 Julien Pommier
  20. This software is provided 'as-is', without any express or implied
  21. warranty. In no event will the authors be held liable for any damages
  22. arising from the use of this software.
  23. Permission is granted to anyone to use this software for any purpose,
  24. including commercial applications, and to alter it and redistribute it
  25. freely, subject to the following restrictions:
  26. 1. The origin of this software must not be misrepresented; you must not
  27. claim that you wrote the original software. If you use this software
  28. in a product, an acknowledgment in the product documentation would be
  29. appreciated but is not required.
  30. 2. Altered source versions must be plainly marked as such, and must not be
  31. misrepresented as being the original software.
  32. 3. This notice may not be removed or altered from any source distribution.
  33. (this is the zlib license)
  34. */
  35. #pragma once
  36. #include "common.hpp"
  37. /** Generate 1.f without accessing memory */
  38. inline __m128 sse_mathfun_one_ps() {
  39. __m128i zeros = _mm_setzero_si128();
  40. __m128i ones = _mm_cmpeq_epi32(zeros, zeros);
  41. __m128i a = _mm_slli_epi32(_mm_srli_epi32(ones, 25), 23);
  42. return _mm_castsi128_ps(a);
  43. }
  44. inline __m128 sse_mathfun_log_ps(__m128 x) {
  45. __m128i emm0;
  46. __m128 one = _mm_set_ps1(1.0);
  47. __m128 invalid_mask = _mm_cmple_ps(x, _mm_setzero_ps());
  48. /* the smallest non denormalized float number */
  49. x = _mm_max_ps(x, _mm_castsi128_ps(_mm_set1_epi32(0x00800000))); /* cut off denormalized stuff */
  50. emm0 = _mm_srli_epi32(_mm_castps_si128(x), 23);
  51. /* keep only the fractional part */
  52. x = _mm_and_ps(x, _mm_castsi128_ps(_mm_set1_epi32(~0x7f800000)));
  53. x = _mm_or_ps(x, _mm_set_ps1(0.5));
  54. emm0 = _mm_sub_epi32(emm0, _mm_set1_epi32(0x7f));
  55. __m128 e = _mm_cvtepi32_ps(emm0);
  56. e = _mm_add_ps(e, one);
  57. /* part2:
  58. if( x < SQRTHF ) {
  59. e -= 1;
  60. x = x + x - 1.0;
  61. } else { x = x - 1.0; }
  62. */
  63. __m128 mask = _mm_cmplt_ps(x, _mm_set_ps1(0.707106781186547524));
  64. __m128 tmp = _mm_and_ps(x, mask);
  65. x = _mm_sub_ps(x, one);
  66. e = _mm_sub_ps(e, _mm_and_ps(one, mask));
  67. x = _mm_add_ps(x, tmp);
  68. __m128 z = _mm_mul_ps(x, x);
  69. __m128 y = _mm_set_ps1(7.0376836292E-2);
  70. y = _mm_mul_ps(y, x);
  71. y = _mm_add_ps(y, _mm_set_ps1(-1.1514610310E-1));
  72. y = _mm_mul_ps(y, x);
  73. y = _mm_add_ps(y, _mm_set_ps1(1.1676998740E-1));
  74. y = _mm_mul_ps(y, x);
  75. y = _mm_add_ps(y, _mm_set_ps1(-1.2420140846E-1));
  76. y = _mm_mul_ps(y, x);
  77. y = _mm_add_ps(y, _mm_set_ps1(1.4249322787E-1));
  78. y = _mm_mul_ps(y, x);
  79. y = _mm_add_ps(y, _mm_set_ps1(-1.6668057665E-1));
  80. y = _mm_mul_ps(y, x);
  81. y = _mm_add_ps(y, _mm_set_ps1(2.0000714765E-1));
  82. y = _mm_mul_ps(y, x);
  83. y = _mm_add_ps(y, _mm_set_ps1(-2.4999993993E-1));
  84. y = _mm_mul_ps(y, x);
  85. y = _mm_add_ps(y, _mm_set_ps1(3.3333331174E-1));
  86. y = _mm_mul_ps(y, x);
  87. y = _mm_mul_ps(y, z);
  88. tmp = _mm_mul_ps(e, _mm_set_ps1(-2.12194440e-4));
  89. y = _mm_add_ps(y, tmp);
  90. tmp = _mm_mul_ps(z, _mm_set_ps1(0.5));
  91. y = _mm_sub_ps(y, tmp);
  92. tmp = _mm_mul_ps(e, _mm_set_ps1(0.693359375));
  93. x = _mm_add_ps(x, y);
  94. x = _mm_add_ps(x, tmp);
  95. x = _mm_or_ps(x, invalid_mask); // negative arg will be NAN
  96. return x;
  97. }
  98. inline __m128 sse_mathfun_exp_ps(__m128 x) {
  99. __m128 tmp = _mm_setzero_ps(), fx;
  100. __m128i emm0;
  101. __m128 one = _mm_set_ps1(1.0);
  102. x = _mm_min_ps(x, _mm_set_ps1(88.3762626647949f));
  103. x = _mm_max_ps(x, _mm_set_ps1(-88.3762626647949f));
  104. /* express exp(x) as exp(g + n*log(2)) */
  105. fx = _mm_mul_ps(x, _mm_set_ps1(1.44269504088896341));
  106. fx = _mm_add_ps(fx, _mm_set_ps1(0.5));
  107. /* how to perform a floorf with SSE: just below */
  108. emm0 = _mm_cvttps_epi32(fx);
  109. tmp = _mm_cvtepi32_ps(emm0);
  110. /* if greater, substract 1 */
  111. __m128 mask = _mm_cmpgt_ps(tmp, fx);
  112. mask = _mm_and_ps(mask, one);
  113. fx = _mm_sub_ps(tmp, mask);
  114. tmp = _mm_mul_ps(fx, _mm_set_ps1(0.693359375));
  115. __m128 z = _mm_mul_ps(fx, _mm_set_ps1(-2.12194440e-4));
  116. x = _mm_sub_ps(x, tmp);
  117. x = _mm_sub_ps(x, z);
  118. z = _mm_mul_ps(x, x);
  119. __m128 y = _mm_set_ps1(1.9875691500E-4);
  120. y = _mm_mul_ps(y, x);
  121. y = _mm_add_ps(y, _mm_set_ps1(1.3981999507E-3));
  122. y = _mm_mul_ps(y, x);
  123. y = _mm_add_ps(y, _mm_set_ps1(8.3334519073E-3));
  124. y = _mm_mul_ps(y, x);
  125. y = _mm_add_ps(y, _mm_set_ps1(4.1665795894E-2));
  126. y = _mm_mul_ps(y, x);
  127. y = _mm_add_ps(y, _mm_set_ps1(1.6666665459E-1));
  128. y = _mm_mul_ps(y, x);
  129. y = _mm_add_ps(y, _mm_set_ps1(5.0000001201E-1));
  130. y = _mm_mul_ps(y, z);
  131. y = _mm_add_ps(y, x);
  132. y = _mm_add_ps(y, one);
  133. /* build 2^n */
  134. emm0 = _mm_cvttps_epi32(fx);
  135. emm0 = _mm_add_epi32(emm0, _mm_set1_epi32(0x7f));
  136. emm0 = _mm_slli_epi32(emm0, 23);
  137. __m128 pow2n = _mm_castsi128_ps(emm0);
  138. y = _mm_mul_ps(y, pow2n);
  139. return y;
  140. }
  141. /* evaluation of 4 sines at onces, using only SSE1+MMX intrinsics so
  142. it runs also on old athlons XPs and the pentium III of your grand
  143. mother.
  144. The code is the exact rewriting of the cephes sinf function.
  145. Precision is excellent as long as x < 8192 (I did not bother to
  146. take into account the special handling they have for greater values
  147. -- it does not return garbage for arguments over 8192, though, but
  148. the extra precision is missing).
  149. Note that it is such that sinf((float)M_PI) = 8.74e-8, which is the
  150. surprising but correct result.
  151. Performance is also surprisingly good, 1.33 times faster than the
  152. macos vsinf SSE2 function, and 1.5 times faster than the
  153. __vrs4_sinf of amd's ACML (which is only available in 64 bits). Not
  154. too bad for an SSE1 function (with no special tuning) !
  155. However the latter libraries probably have a much better handling of NaN,
  156. Inf, denormalized and other special arguments..
  157. On my core 1 duo, the execution of this function takes approximately 95 cycles.
  158. From what I have observed on the experiments with Intel AMath lib, switching to an
  159. SSE2 version would improve the perf by only 10%.
  160. Since it is based on SSE intrinsics, it has to be compiled at -O2 to
  161. deliver full speed.
  162. */
  163. inline __m128 sse_mathfun_sin_ps(__m128 x) { // any x
  164. __m128 xmm1, xmm2 = _mm_setzero_ps(), xmm3, sign_bit, y;
  165. __m128i emm0, emm2;
  166. sign_bit = x;
  167. /* take the absolute value */
  168. const __m128 inv_sign_mask = _mm_castsi128_ps(_mm_set1_epi32(~0x80000000));
  169. x = _mm_and_ps(x, inv_sign_mask);
  170. /* extract the sign bit (upper one) */
  171. const __m128 sign_mask = _mm_castsi128_ps(_mm_set1_epi32(0x80000000));
  172. sign_bit = _mm_and_ps(sign_bit, sign_mask);
  173. /* scale by 4/Pi */
  174. const __m128 cephes_FOPI = _mm_set_ps1(1.27323954473516); // 4 / M_PI
  175. y = _mm_mul_ps(x, cephes_FOPI);
  176. /* store the integer part of y in mm0 */
  177. emm2 = _mm_cvttps_epi32(y);
  178. /* j=(j+1) & (~1) (see the cephes sources) */
  179. emm2 = _mm_add_epi32(emm2, _mm_set1_epi32(1));
  180. emm2 = _mm_and_si128(emm2, _mm_set1_epi32(~1));
  181. y = _mm_cvtepi32_ps(emm2);
  182. /* get the swap sign flag */
  183. emm0 = _mm_and_si128(emm2, _mm_set1_epi32(4));
  184. emm0 = _mm_slli_epi32(emm0, 29);
  185. /* get the polynom selection mask
  186. there is one polynom for 0 <= x <= Pi/4
  187. and another one for Pi/4<x<=Pi/2
  188. Both branches will be computed.
  189. */
  190. emm2 = _mm_and_si128(emm2, _mm_set1_epi32(2));
  191. emm2 = _mm_cmpeq_epi32(emm2, _mm_setzero_si128());
  192. __m128 swap_sign_bit = _mm_castsi128_ps(emm0);
  193. __m128 poly_mask = _mm_castsi128_ps(emm2);
  194. sign_bit = _mm_xor_ps(sign_bit, swap_sign_bit);
  195. /* The magic pass: "Extended precision modular arithmetic"
  196. x = ((x - y * DP1) - y * DP2) - y * DP3; */
  197. xmm1 = _mm_set_ps1(-0.78515625);
  198. xmm2 = _mm_set_ps1(-2.4187564849853515625e-4);
  199. xmm3 = _mm_set_ps1(-3.77489497744594108e-8);
  200. xmm1 = _mm_mul_ps(y, xmm1);
  201. xmm2 = _mm_mul_ps(y, xmm2);
  202. xmm3 = _mm_mul_ps(y, xmm3);
  203. x = _mm_add_ps(x, xmm1);
  204. x = _mm_add_ps(x, xmm2);
  205. x = _mm_add_ps(x, xmm3);
  206. /* Evaluate the first polynom (0 <= x <= Pi/4) */
  207. y = _mm_set_ps1(2.443315711809948E-005);
  208. __m128 z = _mm_mul_ps(x, x);
  209. y = _mm_mul_ps(y, z);
  210. y = _mm_add_ps(y, _mm_set_ps1(-1.388731625493765E-003));
  211. y = _mm_mul_ps(y, z);
  212. y = _mm_add_ps(y, _mm_set_ps1(4.166664568298827E-002));
  213. y = _mm_mul_ps(y, z);
  214. y = _mm_mul_ps(y, z);
  215. __m128 tmp = _mm_mul_ps(z, _mm_set_ps1(0.5));
  216. y = _mm_sub_ps(y, tmp);
  217. y = _mm_add_ps(y, _mm_set_ps1(1.0));
  218. /* Evaluate the second polynom (Pi/4 <= x <= 0) */
  219. __m128 y2 = _mm_set_ps1(-1.9515295891E-4);
  220. y2 = _mm_mul_ps(y2, z);
  221. y2 = _mm_add_ps(y2, _mm_set_ps1(8.3321608736E-3));
  222. y2 = _mm_mul_ps(y2, z);
  223. y2 = _mm_add_ps(y2, _mm_set_ps1(-1.6666654611E-1));
  224. y2 = _mm_mul_ps(y2, z);
  225. y2 = _mm_mul_ps(y2, x);
  226. y2 = _mm_add_ps(y2, x);
  227. /* select the correct result from the two polynoms */
  228. xmm3 = poly_mask;
  229. y2 = _mm_and_ps(xmm3, y2); //, xmm3);
  230. y = _mm_andnot_ps(xmm3, y);
  231. y = _mm_add_ps(y, y2);
  232. /* update the sign */
  233. y = _mm_xor_ps(y, sign_bit);
  234. return y;
  235. }
  236. /* almost the same as sin_ps */
  237. inline __m128 sse_mathfun_cos_ps(__m128 x) { // any x
  238. __m128 xmm1, xmm2 = _mm_setzero_ps(), xmm3, y;
  239. __m128i emm0, emm2;
  240. /* take the absolute value */
  241. const __m128 inv_sign_mask = _mm_castsi128_ps(_mm_set1_epi32(~0x80000000));
  242. x = _mm_and_ps(x, inv_sign_mask);
  243. /* scale by 4/Pi */
  244. const __m128 cephes_FOPI = _mm_set_ps1(1.27323954473516); // 4 / M_PI
  245. y = _mm_mul_ps(x, cephes_FOPI);
  246. /* store the integer part of y in mm0 */
  247. emm2 = _mm_cvttps_epi32(y);
  248. /* j=(j+1) & (~1) (see the cephes sources) */
  249. emm2 = _mm_add_epi32(emm2, _mm_set1_epi32(1));
  250. emm2 = _mm_and_si128(emm2, _mm_set1_epi32(~1));
  251. y = _mm_cvtepi32_ps(emm2);
  252. emm2 = _mm_sub_epi32(emm2, _mm_set1_epi32(2));
  253. /* get the swap sign flag */
  254. emm0 = _mm_andnot_si128(emm2, _mm_set1_epi32(4));
  255. emm0 = _mm_slli_epi32(emm0, 29);
  256. /* get the polynom selection mask */
  257. emm2 = _mm_and_si128(emm2, _mm_set1_epi32(2));
  258. emm2 = _mm_cmpeq_epi32(emm2, _mm_setzero_si128());
  259. __m128 sign_bit = _mm_castsi128_ps(emm0);
  260. __m128 poly_mask = _mm_castsi128_ps(emm2);
  261. /* The magic pass: "Extended precision modular arithmetic"
  262. x = ((x - y * DP1) - y * DP2) - y * DP3; */
  263. xmm1 = _mm_set_ps1(-0.78515625);
  264. xmm2 = _mm_set_ps1(-2.4187564849853515625e-4);
  265. xmm3 = _mm_set_ps1(-3.77489497744594108e-8);
  266. xmm1 = _mm_mul_ps(y, xmm1);
  267. xmm2 = _mm_mul_ps(y, xmm2);
  268. xmm3 = _mm_mul_ps(y, xmm3);
  269. x = _mm_add_ps(x, xmm1);
  270. x = _mm_add_ps(x, xmm2);
  271. x = _mm_add_ps(x, xmm3);
  272. /* Evaluate the first polynom (0 <= x <= Pi/4) */
  273. y = _mm_set_ps1(2.443315711809948E-005);
  274. __m128 z = _mm_mul_ps(x, x);
  275. y = _mm_mul_ps(y, z);
  276. y = _mm_add_ps(y, _mm_set_ps1(-1.388731625493765E-003));
  277. y = _mm_mul_ps(y, z);
  278. y = _mm_add_ps(y, _mm_set_ps1(4.166664568298827E-002));
  279. y = _mm_mul_ps(y, z);
  280. y = _mm_mul_ps(y, z);
  281. __m128 tmp = _mm_mul_ps(z, _mm_set_ps1(0.5));
  282. y = _mm_sub_ps(y, tmp);
  283. y = _mm_add_ps(y, _mm_set_ps1(1.0));
  284. /* Evaluate the second polynom (Pi/4 <= x <= 0) */
  285. __m128 y2 = _mm_set_ps1(-1.9515295891E-4);
  286. y2 = _mm_mul_ps(y2, z);
  287. y2 = _mm_add_ps(y2, _mm_set_ps1(8.3321608736E-3));
  288. y2 = _mm_mul_ps(y2, z);
  289. y2 = _mm_add_ps(y2, _mm_set_ps1(-1.6666654611E-1));
  290. y2 = _mm_mul_ps(y2, z);
  291. y2 = _mm_mul_ps(y2, x);
  292. y2 = _mm_add_ps(y2, x);
  293. /* select the correct result from the two polynoms */
  294. xmm3 = poly_mask;
  295. y2 = _mm_and_ps(xmm3, y2); //, xmm3);
  296. y = _mm_andnot_ps(xmm3, y);
  297. y = _mm_add_ps(y, y2);
  298. /* update the sign */
  299. y = _mm_xor_ps(y, sign_bit);
  300. return y;
  301. }
  302. /* since sin_ps and cos_ps are almost identical, sincos_ps could replace both of them..
  303. it is almost as fast, and gives you a free cosine with your sine */
  304. inline void sse_mathfun_sincos_ps(__m128 x, __m128* s, __m128* c) {
  305. __m128 xmm1, xmm2, xmm3 = _mm_setzero_ps(), sign_bit_sin, y;
  306. __m128i emm0, emm2, emm4;
  307. sign_bit_sin = x;
  308. /* take the absolute value */
  309. const __m128 inv_sign_mask = _mm_castsi128_ps(_mm_set1_epi32(~0x80000000));
  310. x = _mm_and_ps(x, inv_sign_mask);
  311. /* extract the sign bit (upper one) */
  312. const __m128 sign_mask = _mm_castsi128_ps(_mm_set1_epi32(0x80000000));
  313. sign_bit_sin = _mm_and_ps(sign_bit_sin, sign_mask);
  314. /* scale by 4/Pi */
  315. const __m128 cephes_FOPI = _mm_set_ps1(1.27323954473516); // 4 / M_PI
  316. y = _mm_mul_ps(x, cephes_FOPI);
  317. /* store the integer part of y in emm2 */
  318. emm2 = _mm_cvttps_epi32(y);
  319. /* j=(j+1) & (~1) (see the cephes sources) */
  320. emm2 = _mm_add_epi32(emm2, _mm_set1_epi32(1));
  321. emm2 = _mm_and_si128(emm2, _mm_set1_epi32(~1));
  322. y = _mm_cvtepi32_ps(emm2);
  323. emm4 = emm2;
  324. /* get the swap sign flag for the sine */
  325. emm0 = _mm_and_si128(emm2, _mm_set1_epi32(4));
  326. emm0 = _mm_slli_epi32(emm0, 29);
  327. __m128 swap_sign_bit_sin = _mm_castsi128_ps(emm0);
  328. /* get the polynom selection mask for the sine*/
  329. emm2 = _mm_and_si128(emm2, _mm_set1_epi32(2));
  330. emm2 = _mm_cmpeq_epi32(emm2, _mm_setzero_si128());
  331. __m128 poly_mask = _mm_castsi128_ps(emm2);
  332. /* The magic pass: "Extended precision modular arithmetic"
  333. x = ((x - y * DP1) - y * DP2) - y * DP3; */
  334. xmm1 = _mm_set_ps1(-0.78515625);
  335. xmm2 = _mm_set_ps1(-2.4187564849853515625e-4);
  336. xmm3 = _mm_set_ps1(-3.77489497744594108e-8);
  337. xmm1 = _mm_mul_ps(y, xmm1);
  338. xmm2 = _mm_mul_ps(y, xmm2);
  339. xmm3 = _mm_mul_ps(y, xmm3);
  340. x = _mm_add_ps(x, xmm1);
  341. x = _mm_add_ps(x, xmm2);
  342. x = _mm_add_ps(x, xmm3);
  343. emm4 = _mm_sub_epi32(emm4, _mm_set1_epi32(2));
  344. emm4 = _mm_andnot_si128(emm4, _mm_set1_epi32(4));
  345. emm4 = _mm_slli_epi32(emm4, 29);
  346. __m128 sign_bit_cos = _mm_castsi128_ps(emm4);
  347. sign_bit_sin = _mm_xor_ps(sign_bit_sin, swap_sign_bit_sin);
  348. /* Evaluate the first polynom (0 <= x <= Pi/4) */
  349. __m128 z = _mm_mul_ps(x, x);
  350. y = _mm_set_ps1(2.443315711809948E-005);
  351. y = _mm_mul_ps(y, z);
  352. y = _mm_add_ps(y, _mm_set_ps1(-1.388731625493765E-003));
  353. y = _mm_mul_ps(y, z);
  354. y = _mm_add_ps(y, _mm_set_ps1(4.166664568298827E-002));
  355. y = _mm_mul_ps(y, z);
  356. y = _mm_mul_ps(y, z);
  357. __m128 tmp = _mm_mul_ps(z, _mm_set_ps1(0.5));
  358. y = _mm_sub_ps(y, tmp);
  359. y = _mm_add_ps(y, _mm_set_ps1(1.0));
  360. /* Evaluate the second polynom (Pi/4 <= x <= 0) */
  361. __m128 y2 = _mm_set_ps1(-1.9515295891E-4);
  362. y2 = _mm_mul_ps(y2, z);
  363. y2 = _mm_add_ps(y2, _mm_set_ps1(8.3321608736E-3));
  364. y2 = _mm_mul_ps(y2, z);
  365. y2 = _mm_add_ps(y2, _mm_set_ps1(-1.6666654611E-1));
  366. y2 = _mm_mul_ps(y2, z);
  367. y2 = _mm_mul_ps(y2, x);
  368. y2 = _mm_add_ps(y2, x);
  369. /* select the correct result from the two polynoms */
  370. xmm3 = poly_mask;
  371. __m128 ysin2 = _mm_and_ps(xmm3, y2);
  372. __m128 ysin1 = _mm_andnot_ps(xmm3, y);
  373. y2 = _mm_sub_ps(y2, ysin2);
  374. y = _mm_sub_ps(y, ysin1);
  375. xmm1 = _mm_add_ps(ysin1, ysin2);
  376. xmm2 = _mm_add_ps(y, y2);
  377. /* update the sign */
  378. *s = _mm_xor_ps(xmm1, sign_bit_sin);
  379. *c = _mm_xor_ps(xmm2, sign_bit_cos);
  380. }