CpuGeneratorsAVX.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. #include "CpuGenerators.h"
  2. #include <immintrin.h>
  3. #include <omp.h>
  4. #include <memory>
  5. using mnd::CpuGeneratorAvxFloat;
  6. using mnd::CpuGeneratorAvxDouble;
  7. void CpuGeneratorAvxFloat::generate(const mnd::MandelInfo& info, float* data)
  8. {
  9. using T = float;
  10. const MandelViewport& view = info.view;
  11. omp_set_num_threads(2 * omp_get_num_procs());
  12. #pragma omp parallel for schedule(static, 1)
  13. for (long j = 0; j < info.bHeight; j++) {
  14. T y = T(view.y) + T(j) * T(view.height / info.bHeight);
  15. long i = 0;
  16. for (i; i < info.bWidth; i += 8) {
  17. __m256 xs = {
  18. float(view.x + double(i) * view.width / info.bWidth),
  19. float(view.x + double(i + 1) * view.width / info.bWidth),
  20. float(view.x + double(i + 2) * view.width / info.bWidth),
  21. float(view.x + double(i + 3) * view.width / info.bWidth),
  22. float(view.x + double(i + 4) * view.width / info.bWidth),
  23. float(view.x + double(i + 5) * view.width / info.bWidth),
  24. float(view.x + double(i + 6) * view.width / info.bWidth),
  25. float(view.x + double(i + 7) * view.width / info.bWidth)
  26. };
  27. __m256 counter = {0, 0, 0, 0, 0, 0, 0, 0};
  28. __m256 adder = {1, 1, 1, 1, 1, 1, 1, 1};
  29. __m256 threshold = {16.0f, 16.0f, 16.0f, 16.0f, 16.0f, 16.0f, 16.0f, 16.0f};
  30. __m256 ys = {y, y, y, y, y, y, y, y};
  31. __m256 a = xs;
  32. __m256 b = ys;
  33. for (int k = 0; k < info.maxIter; k++) {
  34. __m256 aa = _mm256_mul_ps(a, a);
  35. __m256 bb = _mm256_mul_ps(b, b);
  36. __m256 abab = _mm256_mul_ps(a, b); abab = _mm256_add_ps(abab, abab);
  37. a = _mm256_add_ps(_mm256_sub_ps(aa, bb), xs);
  38. b = _mm256_add_ps(abab, ys);
  39. __m256i cmp = _mm256_castps_si256(_mm256_cmp_ps(_mm256_add_ps(aa, bb), threshold, _CMP_LE_OQ));
  40. adder = _mm256_and_ps(adder, _mm256_castsi256_ps(cmp));
  41. counter = _mm256_add_ps(counter, adder);
  42. if ((k & 0x7) == 0 && _mm256_testz_si256(cmp, cmp) != 0) {
  43. break;
  44. }
  45. }
  46. auto alignVec = [](float* data) -> float* {
  47. void* aligned = data;
  48. ::size_t length = 64;
  49. std::align(32, 8 * sizeof(float), aligned, length);
  50. return static_cast<float*>(aligned);
  51. };
  52. float resData[16];
  53. float* ftRes = alignVec(resData);
  54. _mm256_store_ps(ftRes, counter);
  55. for (int k = 0; k < 8 && i + k < info.bWidth; k++)
  56. data[i + k + j * info.bWidth] = ftRes[k] > 0 ? ftRes[k] : info.maxIter;
  57. }
  58. }
  59. }
  60. void CpuGeneratorAvxDouble::generate(const mnd::MandelInfo& info, float* data)
  61. {
  62. using T = double;
  63. const MandelViewport& view = info.view;
  64. omp_set_num_threads(2 * omp_get_num_procs());
  65. #pragma omp parallel for
  66. for (long j = 0; j < info.bHeight; j++) {
  67. T y = T(view.y) + T(j) * view.height / info.bHeight;
  68. long i = 0;
  69. for (i; i < info.bWidth; i += 4) {
  70. __m256d xs = {
  71. double(view.x) + double(i) * view.width / info.bWidth,
  72. double(view.x) + double(i + 1) * view.width / info.bWidth,
  73. double(view.x) + double(i + 2) * view.width / info.bWidth,
  74. double(view.x) + double(i + 3) * view.width / info.bWidth
  75. };
  76. int itRes[4] = { 0, 0, 0, 0 };
  77. __m256d threshold = { 16.0, 16.0, 16.0, 16.0 };
  78. __m256d counter = { 0, 0, 0, 0 };
  79. __m256d adder = { 1, 1, 1, 1 };
  80. __m256d ys = { y, y, y, y };
  81. __m256d a = xs;
  82. __m256d b = ys;
  83. for (int k = 0; k < info.maxIter; k++) {
  84. __m256d aa = _mm256_mul_pd(a, a);
  85. __m256d bb = _mm256_mul_pd(b, b);
  86. __m256d abab = _mm256_mul_pd(a, b); abab = _mm256_add_pd(abab, abab);
  87. a = _mm256_add_pd(_mm256_sub_pd(aa, bb), xs);
  88. b = _mm256_add_pd(abab, ys);
  89. __m256i cmp = _mm256_castpd_si256(_mm256_cmp_pd(_mm256_add_pd(aa, bb), threshold, _CMP_LE_OQ));
  90. adder = _mm256_and_pd(adder, _mm256_castsi256_pd(cmp));
  91. counter = _mm256_add_pd(counter, adder);
  92. if ((k & 0x7) == 0 && _mm256_testz_si256(cmp, cmp) != 0) {
  93. break;
  94. }
  95. }
  96. auto alignVec = [](double* data) -> double* {
  97. void* aligned = data;
  98. ::size_t length = 64;
  99. std::align(32, 4 * sizeof(double), aligned, length);
  100. return static_cast<double*>(aligned);
  101. };
  102. double resData[8];
  103. double* ftRes = alignVec(resData);
  104. _mm256_store_pd(ftRes, counter);
  105. for (int k = 0; k < 4 && i + k < info.bWidth; k++)
  106. data[i + k + j * info.bWidth] = ftRes[k] > 0 ? float(ftRes[k]) : info.maxIter;
  107. }
  108. }
  109. }