x86.h 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. /*
  2. * Copyright (c), Recep Aslantas.
  3. *
  4. * MIT License (MIT), http://opensource.org/licenses/MIT
  5. * Full license can be found in the LICENSE file
  6. */
  7. #ifndef cglm_simd_x86_h
  8. #define cglm_simd_x86_h
  9. #include "intrin.h"
  10. #ifdef CGLM_SIMD_x86
  11. #ifdef CGLM_ALL_UNALIGNED
  12. # define glmm_load(p) _mm_loadu_ps(p)
  13. # define glmm_store(p, a) _mm_storeu_ps(p, a)
  14. #else
  15. # define glmm_load(p) _mm_load_ps(p)
  16. # define glmm_store(p, a) _mm_store_ps(p, a)
  17. #endif
  18. #define glmm_128 __m128
  19. #ifdef __AVX__
  20. # define glmm_shuff1(xmm, z, y, x, w) \
  21. _mm_permute_ps((xmm), _MM_SHUFFLE(z, y, x, w))
  22. #else
  23. # if !defined(CGLM_NO_INT_DOMAIN) && defined(__SSE2__)
  24. # define glmm_shuff1(xmm, z, y, x, w) \
  25. _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(xmm), \
  26. _MM_SHUFFLE(z, y, x, w)))
  27. # else
  28. # define glmm_shuff1(xmm, z, y, x, w) \
  29. _mm_shuffle_ps(xmm, xmm, _MM_SHUFFLE(z, y, x, w))
  30. # endif
  31. #endif
  32. #define glmm_splat(x, lane) glmm_shuff1(x, lane, lane, lane, lane)
  33. #ifdef __AVX__
  34. # define glmm_set1(x) _mm_broadcast_ss(&x)
  35. # define glmm_set1_ptr(x) _mm_broadcast_ss(x)
  36. # define glmm_set1_rval(x) _mm_set1_ps(x)
  37. # ifdef __AVX2__
  38. # define glmm_splat_x(x) _mm_broadcastss_ps(x)
  39. # else
  40. # define glmm_splat_x(x) _mm_permute_ps(x, _MM_SHUFFLE(0, 0, 0, 0))
  41. # endif
  42. # define glmm_splat_y(x) _mm_permute_ps(x, _MM_SHUFFLE(1, 1, 1, 1))
  43. # define glmm_splat_z(x) _mm_permute_ps(x, _MM_SHUFFLE(2, 2, 2, 2))
  44. # define glmm_splat_w(x) _mm_permute_ps(x, _MM_SHUFFLE(3, 3, 3, 3))
  45. #else
  46. # define glmm_set1(x) _mm_set1_ps(x)
  47. # define glmm_set1_ptr(x) _mm_set1_ps(*x)
  48. # define glmm_set1_rval(x) _mm_set1_ps(x)
  49. # define glmm_splat_x(x) glmm_splat(x, 0)
  50. # define glmm_splat_y(x) glmm_splat(x, 1)
  51. # define glmm_splat_z(x) glmm_splat(x, 2)
  52. # define glmm_splat_w(x) glmm_splat(x, 3)
  53. #endif
  54. #ifdef __AVX__
  55. # ifdef CGLM_ALL_UNALIGNED
  56. # define glmm_load256(p) _mm256_loadu_ps(p)
  57. # define glmm_store256(p, a) _mm256_storeu_ps(p, a)
  58. # else
  59. # define glmm_load256(p) _mm256_load_ps(p)
  60. # define glmm_store256(p, a) _mm256_store_ps(p, a)
  61. # endif
  62. #endif
  63. /* Note that `0x80000000` corresponds to `INT_MIN` for a 32-bit int. */
  64. #if defined(__SSE2__)
  65. # define GLMM_NEGZEROf ((int)0x80000000) /* 0x80000000 ---> -0.0f */
  66. # define GLMM_POSZEROf ((int)0x00000000) /* 0x00000000 ---> +0.0f */
  67. #else
  68. # ifdef CGLM_FAST_MATH
  69. union { int i; float f; } static GLMM_NEGZEROf_TU = { .i = (int)0x80000000 };
  70. # define GLMM_NEGZEROf GLMM_NEGZEROf_TU.f
  71. # define GLMM_POSZEROf 0.0f
  72. # else
  73. # define GLMM_NEGZEROf -0.0f
  74. # define GLMM_POSZEROf 0.0f
  75. # endif
  76. #endif
  77. #if defined(__SSE2__)
  78. # define GLMM__SIGNMASKf(X, Y, Z, W) \
  79. _mm_castsi128_ps(_mm_set_epi32(X, Y, Z, W))
  80. /* _mm_set_ps(X, Y, Z, W); */
  81. #else
  82. # define GLMM__SIGNMASKf(X, Y, Z, W) _mm_set_ps(X, Y, Z, W)
  83. #endif
  84. #define glmm_float32x4_SIGNMASK_PNPN GLMM__SIGNMASKf(GLMM_POSZEROf, GLMM_NEGZEROf, GLMM_POSZEROf, GLMM_NEGZEROf)
  85. #define glmm_float32x4_SIGNMASK_NPNP GLMM__SIGNMASKf(GLMM_NEGZEROf, GLMM_POSZEROf, GLMM_NEGZEROf, GLMM_POSZEROf)
  86. #define glmm_float32x4_SIGNMASK_NPPN GLMM__SIGNMASKf(GLMM_NEGZEROf, GLMM_POSZEROf, GLMM_POSZEROf, GLMM_NEGZEROf)
  87. /* fasth math prevents -0.0f to work */
  88. #if defined(__SSE2__)
  89. # define glmm_float32x4_SIGNMASK_NEG _mm_castsi128_ps(_mm_set1_epi32(GLMM_NEGZEROf)) /* _mm_set1_ps(-0.0f) */
  90. #else
  91. # define glmm_float32x4_SIGNMASK_NEG glmm_set1(GLMM_NEGZEROf)
  92. #endif
  93. #define glmm_float32x8_SIGNMASK_NEG _mm256_castsi256_ps(_mm256_set1_epi32(GLMM_NEGZEROf))
  94. static inline
  95. __m128
  96. glmm_abs(__m128 x) {
  97. return _mm_andnot_ps(glmm_float32x4_SIGNMASK_NEG, x);
  98. }
  99. static inline __m128 glmm_min(__m128 a, __m128 b) { return _mm_min_ps(a, b); }
  100. static inline __m128 glmm_max(__m128 a, __m128 b) { return _mm_max_ps(a, b); }
  101. static inline
  102. __m128
  103. glmm_vhadd(__m128 v) {
  104. __m128 x0;
  105. x0 = _mm_add_ps(v, glmm_shuff1(v, 0, 1, 2, 3));
  106. x0 = _mm_add_ps(x0, glmm_shuff1(x0, 1, 0, 0, 1));
  107. return x0;
  108. }
  109. static inline
  110. __m128
  111. glmm_vhadds(__m128 v) {
  112. #if defined(__SSE3__)
  113. __m128 shuf, sums;
  114. shuf = _mm_movehdup_ps(v);
  115. sums = _mm_add_ps(v, shuf);
  116. shuf = _mm_movehl_ps(shuf, sums);
  117. sums = _mm_add_ss(sums, shuf);
  118. return sums;
  119. #else
  120. __m128 shuf, sums;
  121. shuf = glmm_shuff1(v, 2, 3, 0, 1);
  122. sums = _mm_add_ps(v, shuf);
  123. shuf = _mm_movehl_ps(shuf, sums);
  124. sums = _mm_add_ss(sums, shuf);
  125. return sums;
  126. #endif
  127. }
  128. static inline
  129. float
  130. glmm_hadd(__m128 v) {
  131. return _mm_cvtss_f32(glmm_vhadds(v));
  132. }
  133. static inline
  134. __m128
  135. glmm_vhmin(__m128 v) {
  136. __m128 x0, x1, x2;
  137. x0 = _mm_movehl_ps(v, v); /* [2, 3, 2, 3] */
  138. x1 = _mm_min_ps(x0, v); /* [0|2, 1|3, 2|2, 3|3] */
  139. x2 = glmm_splat(x1, 1); /* [1|3, 1|3, 1|3, 1|3] */
  140. return _mm_min_ss(x1, x2);
  141. }
  142. static inline
  143. float
  144. glmm_hmin(__m128 v) {
  145. return _mm_cvtss_f32(glmm_vhmin(v));
  146. }
  147. static inline
  148. __m128
  149. glmm_vhmax(__m128 v) {
  150. __m128 x0, x1, x2;
  151. x0 = _mm_movehl_ps(v, v); /* [2, 3, 2, 3] */
  152. x1 = _mm_max_ps(x0, v); /* [0|2, 1|3, 2|2, 3|3] */
  153. x2 = glmm_splat(x1, 1); /* [1|3, 1|3, 1|3, 1|3] */
  154. return _mm_max_ss(x1, x2);
  155. }
  156. static inline
  157. float
  158. glmm_hmax(__m128 v) {
  159. return _mm_cvtss_f32(glmm_vhmax(v));
  160. }
  161. static inline
  162. __m128
  163. glmm_vdots(__m128 a, __m128 b) {
  164. #if (defined(__SSE4_1__) || defined(__SSE4_2__)) && defined(CGLM_SSE4_DOT)
  165. return _mm_dp_ps(a, b, 0xFF);
  166. #elif defined(__SSE3__) && defined(CGLM_SSE3_DOT)
  167. __m128 x0, x1;
  168. x0 = _mm_mul_ps(a, b);
  169. x1 = _mm_hadd_ps(x0, x0);
  170. return _mm_hadd_ps(x1, x1);
  171. #else
  172. return glmm_vhadds(_mm_mul_ps(a, b));
  173. #endif
  174. }
  175. static inline
  176. __m128
  177. glmm_vdot(__m128 a, __m128 b) {
  178. #if (defined(__SSE4_1__) || defined(__SSE4_2__)) && defined(CGLM_SSE4_DOT)
  179. return _mm_dp_ps(a, b, 0xFF);
  180. #elif defined(__SSE3__) && defined(CGLM_SSE3_DOT)
  181. __m128 x0, x1;
  182. x0 = _mm_mul_ps(a, b);
  183. x1 = _mm_hadd_ps(x0, x0);
  184. return _mm_hadd_ps(x1, x1);
  185. #else
  186. __m128 x0;
  187. x0 = _mm_mul_ps(a, b);
  188. x0 = _mm_add_ps(x0, glmm_shuff1(x0, 1, 0, 3, 2));
  189. return _mm_add_ps(x0, glmm_shuff1(x0, 0, 1, 0, 1));
  190. #endif
  191. }
  192. static inline
  193. float
  194. glmm_dot(__m128 a, __m128 b) {
  195. return _mm_cvtss_f32(glmm_vdots(a, b));
  196. }
  197. static inline
  198. float
  199. glmm_norm(__m128 a) {
  200. return _mm_cvtss_f32(_mm_sqrt_ss(glmm_vhadds(_mm_mul_ps(a, a))));
  201. }
  202. static inline
  203. float
  204. glmm_norm2(__m128 a) {
  205. return _mm_cvtss_f32(glmm_vhadds(_mm_mul_ps(a, a)));
  206. }
  207. static inline
  208. float
  209. glmm_norm_one(__m128 a) {
  210. return _mm_cvtss_f32(glmm_vhadds(glmm_abs(a)));
  211. }
  212. static inline
  213. float
  214. glmm_norm_inf(__m128 a) {
  215. return _mm_cvtss_f32(glmm_vhmax(glmm_abs(a)));
  216. }
  217. #if defined(__SSE2__)
  218. static inline
  219. __m128
  220. glmm_load3(float v[3]) {
  221. __m128i xy;
  222. __m128 z;
  223. xy = _mm_loadl_epi64(CGLM_CASTPTR_ASSUME_ALIGNED(v, const __m128i));
  224. z = _mm_load_ss(&v[2]);
  225. return _mm_movelh_ps(_mm_castsi128_ps(xy), z);
  226. }
  227. static inline
  228. void
  229. glmm_store3(float v[3], __m128 vx) {
  230. _mm_storel_pi(CGLM_CASTPTR_ASSUME_ALIGNED(v, __m64), vx);
  231. _mm_store_ss(&v[2], glmm_shuff1(vx, 2, 2, 2, 2));
  232. }
  233. #endif
  234. static inline
  235. __m128
  236. glmm_div(__m128 a, __m128 b) {
  237. return _mm_div_ps(a, b);
  238. }
  239. /* enable FMA macro for MSVC? */
  240. #if defined(_MSC_VER) && !defined(__FMA__) && defined(__AVX2__)
  241. # define __FMA__ 1
  242. #endif
  243. static inline
  244. __m128
  245. glmm_fmadd(__m128 a, __m128 b, __m128 c) {
  246. #ifdef __FMA__
  247. return _mm_fmadd_ps(a, b, c);
  248. #else
  249. return _mm_add_ps(c, _mm_mul_ps(a, b));
  250. #endif
  251. }
  252. static inline
  253. __m128
  254. glmm_fnmadd(__m128 a, __m128 b, __m128 c) {
  255. #ifdef __FMA__
  256. return _mm_fnmadd_ps(a, b, c);
  257. #else
  258. return _mm_sub_ps(c, _mm_mul_ps(a, b));
  259. #endif
  260. }
  261. static inline
  262. __m128
  263. glmm_fmsub(__m128 a, __m128 b, __m128 c) {
  264. #ifdef __FMA__
  265. return _mm_fmsub_ps(a, b, c);
  266. #else
  267. return _mm_sub_ps(_mm_mul_ps(a, b), c);
  268. #endif
  269. }
  270. static inline
  271. __m128
  272. glmm_fnmsub(__m128 a, __m128 b, __m128 c) {
  273. #ifdef __FMA__
  274. return _mm_fnmsub_ps(a, b, c);
  275. #else
  276. return _mm_xor_ps(_mm_add_ps(_mm_mul_ps(a, b), c),
  277. glmm_float32x4_SIGNMASK_NEG);
  278. #endif
  279. }
  280. #if defined(__AVX__)
  281. static inline
  282. __m256
  283. glmm256_fmadd(__m256 a, __m256 b, __m256 c) {
  284. #ifdef __FMA__
  285. return _mm256_fmadd_ps(a, b, c);
  286. #else
  287. return _mm256_add_ps(c, _mm256_mul_ps(a, b));
  288. #endif
  289. }
  290. static inline
  291. __m256
  292. glmm256_fnmadd(__m256 a, __m256 b, __m256 c) {
  293. #ifdef __FMA__
  294. return _mm256_fnmadd_ps(a, b, c);
  295. #else
  296. return _mm256_sub_ps(c, _mm256_mul_ps(a, b));
  297. #endif
  298. }
  299. static inline
  300. __m256
  301. glmm256_fmsub(__m256 a, __m256 b, __m256 c) {
  302. #ifdef __FMA__
  303. return _mm256_fmsub_ps(a, b, c);
  304. #else
  305. return _mm256_sub_ps(_mm256_mul_ps(a, b), c);
  306. #endif
  307. }
  308. static inline
  309. __m256
  310. glmm256_fnmsub(__m256 a, __m256 b, __m256 c) {
  311. #ifdef __FMA__
  312. return _mm256_fmsub_ps(a, b, c);
  313. #else
  314. return _mm256_xor_ps(_mm256_sub_ps(_mm256_mul_ps(a, b), c),
  315. glmm_float32x8_SIGNMASK_NEG);
  316. #endif
  317. }
  318. #endif
  319. #endif
  320. #endif /* cglm_simd_x86_h */