CpuGeneratorsAVX512.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. #include "CpuGenerators.h"
  2. #include <immintrin.h>
  3. #include <omp.h>
  4. #include <memory>
  5. using mnd::CpuGenerator;
  6. namespace mnd
  7. {
  8. template class CpuGenerator<float, mnd::X86_AVX_512, false>;
  9. template class CpuGenerator<float, mnd::X86_AVX_512, true>;
  10. template class CpuGenerator<double, mnd::X86_AVX_512, false>;
  11. template class CpuGenerator<double, mnd::X86_AVX_512, true>;
  12. }
  13. template<bool parallel>
  14. void CpuGenerator<float, mnd::X86_AVX_512, parallel>::generate(const mnd::MandelInfo& info, float* data)
  15. {
  16. using T = float;
  17. const MandelViewport& view = info.view;
  18. const float dppf = float(view.width / info.bWidth);
  19. const float viewxf = float(view.x);
  20. __m512 viewx = { viewxf, viewxf, viewxf, viewxf, viewxf, viewxf, viewxf, viewxf,
  21. viewxf, viewxf, viewxf, viewxf, viewxf, viewxf, viewxf, viewxf };
  22. __m512 dpp = { dppf, dppf, dppf, dppf, dppf, dppf, dppf, dppf,
  23. dppf, dppf, dppf, dppf, dppf, dppf, dppf, dppf };
  24. if constexpr(parallel)
  25. omp_set_num_threads(omp_get_num_procs());
  26. #pragma omp parallel for schedule(static, 1) if (parallel)
  27. for (long j = 0; j < info.bHeight; j++) {
  28. T y = T(view.y + double(j) * view.height / info.bHeight);
  29. __m512 ys = { y, y, y, y, y, y, y, y, y, y, y, y, y, y, y, y };
  30. long i = 0;
  31. for (i; i < info.bWidth; i += 16) {
  32. __m512 pixc = { float(i), float(i + 1), float(i + 2), float(i + 3), float(i + 4), float(i + 5), float(i + 6), float(i + 7),
  33. float(i + 8), float(i + 9), float(i + 10), float(i + 11), float(i + 12), float(i + 13), float(i + 14), float(i + 15) };
  34. __m512 xs = _mm512_fmadd_ps(dpp, pixc, viewx);
  35. __m512 counter = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  36. __m512 adder = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
  37. __m512 two = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };
  38. __m512 resultsa = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  39. __m512 resultsb = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  40. __m512 threshold = { 16.0f, 16.0f, 16.0f, 16.0f, 16.0f, 16.0f, 16.0f, 16.0f,
  41. 16.0f, 16.0f, 16.0f, 16.0f, 16.0f, 16.0f, 16.0f, 16.0f };
  42. __m512 a = xs;
  43. __m512 b = ys;
  44. if (info.smooth) {
  45. for (int k = 0; k < info.maxIter; k++) {
  46. __m512 aa = _mm512_mul_ps(a, a);
  47. __m512 abab = _mm512_mul_ps(a, b);
  48. __mmask16 cmp = _mm512_cmp_ps_mask(_mm512_fmadd_ps(b, b, aa), threshold, _CMP_LE_OQ);
  49. a = _mm512_sub_ps(aa, _mm512_fmsub_ps(b, b, xs));
  50. b = _mm512_fmadd_ps(two, abab, ys);
  51. counter = _mm512_mask_add_ps(counter, cmp, counter, adder);
  52. resultsa = _mm512_mask_blend_ps(cmp, resultsa, a);
  53. resultsb = _mm512_mask_blend_ps(cmp, resultsb, b);
  54. if (cmp == 0) {
  55. break;
  56. }
  57. }
  58. }
  59. else {
  60. for (int k = 0; k < info.maxIter; k++) {
  61. __m512 aa = _mm512_mul_ps(a, a);
  62. __m512 abab = _mm512_mul_ps(a, b);
  63. __mmask16 cmp = _mm512_cmp_ps_mask(_mm512_fmadd_ps(b, b, aa), threshold, _CMP_LE_OQ);
  64. a = _mm512_sub_ps(aa, _mm512_fmsub_ps(b, b, xs));
  65. b = _mm512_fmadd_ps(two, abab, ys);
  66. counter = _mm512_mask_add_ps(counter, cmp, counter, adder);
  67. if (cmp == 0) {
  68. break;
  69. }
  70. }
  71. }
  72. auto alignVec = [](float* data) -> float* {
  73. void* aligned = data;
  74. ::size_t length = 64 * sizeof(float);
  75. std::align(64, 48 * sizeof(float), aligned, length);
  76. return static_cast<float*>(aligned);
  77. };
  78. float resData[64];
  79. float* ftRes = alignVec(resData);
  80. float* resa = ftRes + 16;
  81. float* resb = ftRes + 32;
  82. _mm512_store_ps(ftRes, counter);
  83. if (info.smooth) {
  84. _mm512_store_ps(resa, resultsa);
  85. _mm512_store_ps(resb, resultsb);
  86. }
  87. for (int k = 0; k < 16 && i + k < info.bWidth; k++) {
  88. if (info.smooth) {
  89. data[i + k + j * info.bWidth] = ftRes[k] <= 0 ? info.maxIter :
  90. ftRes[k] >= info.maxIter ? info.maxIter :
  91. ((float)ftRes[k]) + 1 - ::log(::log(resa[k] * resa[k] + resb[k] * resb[k]) / 2) / ::log(2.0f);
  92. }
  93. else {
  94. data[i + k + j * info.bWidth] = ftRes[k] <= 0 ? info.maxIter : ftRes[k];
  95. }
  96. }
  97. }
  98. }
  99. }
  100. template<bool parallel>
  101. void CpuGenerator<double, mnd::X86_AVX_512, parallel>::generate(const mnd::MandelInfo& info, float* data)
  102. {
  103. using T = double;
  104. const MandelViewport& view = info.view;
  105. const double dppf = double(view.width / info.bWidth);
  106. const double viewxf = double(view.x);
  107. __m512d viewx = { viewxf, viewxf, viewxf, viewxf, viewxf, viewxf, viewxf, viewxf };
  108. __m512d dpp = { dppf, dppf, dppf, dppf, dppf, dppf, dppf, dppf };
  109. if constexpr(parallel)
  110. omp_set_num_threads(omp_get_num_procs());
  111. #pragma omp parallel for schedule(static, 1) if (parallel)
  112. for (long j = 0; j < info.bHeight; j++) {
  113. T y = T(view.y + double(j) * view.height / info.bHeight);
  114. __m512d ys = { y, y, y, y, y, y, y, y };
  115. long i = 0;
  116. for (i; i < info.bWidth; i += 8) {
  117. __m512d pixc = { double(i), double(i + 1), double(i + 2), double(i + 3), double(i + 4), double(i + 5), double(i + 6), double(i + 7) };
  118. __m512d xs = _mm512_fmadd_pd(dpp, pixc, viewx);
  119. __m512d counter = { 0, 0, 0, 0, 0, 0, 0, 0 };
  120. __m512d adder = { 1, 1, 1, 1, 1, 1, 1, 1 };
  121. __m512d two = { 2, 2, 2, 2, 2, 2, 2, 2 };
  122. __m512d resultsa = { 0, 0, 0, 0, 0, 0, 0, 0 };
  123. __m512d resultsb = { 0, 0, 0, 0, 0, 0, 0, 0 };
  124. __m512d threshold = { 16.0f, 16.0f, 16.0f, 16.0f, 16.0f, 16.0f, 16.0f, 16.0f };
  125. __m512d a = xs;
  126. __m512d b = ys;
  127. if (info.smooth) {
  128. for (int k = 0; k < info.maxIter; k++) {
  129. __m512d aa = _mm512_mul_pd(a, a);
  130. __m512d ab = _mm512_mul_pd(a, b);
  131. __mmask8 cmp = _mm512_cmp_pd_mask(_mm512_fmadd_pd(b, b, aa), threshold, _CMP_LE_OQ);
  132. a = _mm512_sub_pd(aa, _mm512_fmsub_pd(b, b, xs));
  133. b = _mm512_fmadd_pd(two, ab, ys);
  134. resultsa = _mm512_mask_blend_pd(cmp, resultsa, a);
  135. resultsb = _mm512_mask_blend_pd(cmp, resultsb, b);
  136. counter = _mm512_mask_add_pd(counter, cmp, counter, adder);
  137. if (cmp == 0) {
  138. break;
  139. }
  140. }
  141. }
  142. else {
  143. for (int k = 0; k < info.maxIter; k++) {
  144. __m512d aa = _mm512_mul_pd(a, a);
  145. __m512d ab = _mm512_mul_pd(a, b);
  146. __mmask8 cmp = _mm512_cmp_pd_mask(_mm512_fmadd_pd(b, b, aa), threshold, _CMP_LE_OQ);
  147. a = _mm512_sub_pd(aa, _mm512_fmsub_pd(b, b, xs));
  148. b = _mm512_fmadd_pd(two, ab, ys);
  149. counter = _mm512_mask_add_pd(counter, cmp, counter, adder);
  150. if (cmp == 0) {
  151. break;
  152. }
  153. }
  154. }
  155. auto alignVec = [](double* data) -> double* {
  156. void* aligned = data;
  157. ::size_t length = 32 * sizeof(double);
  158. std::align(64, 24 * sizeof(double), aligned, length);
  159. return static_cast<double*>(aligned);
  160. };
  161. double resData[64];
  162. double* ftRes = alignVec(resData);
  163. double* resa = ftRes + 8;
  164. double* resb = ftRes + 16;
  165. _mm512_store_pd(ftRes, counter);
  166. if (info.smooth) {
  167. _mm512_store_pd(resa, resultsa);
  168. _mm512_store_pd(resb, resultsb);
  169. }
  170. for (int k = 0; k < 8 && i + k < info.bWidth; k++) {
  171. if (info.smooth) {
  172. data[i + k + j * info.bWidth] = ftRes[k] <= 0 ? info.maxIter :
  173. ftRes[k] >= info.maxIter ? info.maxIter :
  174. ((float)ftRes[k]) + 1 - ::log(::log((float) (resa[k] * resa[k] + resb[k] * resb[k])) / 2) / ::log(2.0f);
  175. }
  176. else {
  177. data[i + k + j * info.bWidth] = ftRes[k] <= 0 ? info.maxIter : ftRes[k];
  178. }
  179. }
  180. }
  181. }
  182. }