NaiveIRGenerator.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. #include "NaiveIRGenerator.h"
  2. #include <omp.h>
  3. using mnd::NaiveIRGenerator;
  4. namespace mnd
  5. {
  6. template class NaiveIRGenerator<float>;
  7. template class NaiveIRGenerator<double>;
  8. template class NaiveIRGenerator<mnd::DoubleDouble>;
  9. template class NaiveIRGenerator<mnd::QuadDouble>;
  10. }
  11. namespace eval {
  12. struct Load;
  13. struct Store;
  14. struct Add;
  15. struct Sub;
  16. struct Mul;
  17. struct Div;
  18. struct Neg;
  19. struct Atan;
  20. struct Pow;
  21. struct Cos;
  22. struct Sin;
  23. struct Exp;
  24. struct Ln;
  25. using EvalNode = std::variant<
  26. Load,
  27. Store,
  28. Add,
  29. Sub,
  30. Mul,
  31. Div,
  32. Neg,
  33. Atan,
  34. Pow,
  35. Cos,
  36. Sin,
  37. Exp,
  38. Ln
  39. >;
  40. struct Load { int index; };
  41. struct Store { int index; };
  42. struct BinaryOperation
  43. {
  44. std::unique_ptr<EvalNode> a;
  45. std::unique_ptr<EvalNode> b;
  46. };
  47. struct UnaryOperation
  48. {
  49. std::unique_ptr<EvalNode> a;
  50. };
  51. struct Add : BinaryOperation {};
  52. struct Sub : BinaryOperation {};
  53. struct Mul : BinaryOperation {};
  54. struct Div : BinaryOperation {};
  55. struct Neg : UnaryOperation {};
  56. struct Atan : BinaryOperation {};
  57. struct Pow : BinaryOperation {};
  58. struct Cos : UnaryOperation {};
  59. struct Sin : UnaryOperation {};
  60. struct Exp : UnaryOperation {};
  61. struct Ln : UnaryOperation {};
  62. }
  63. template<typename T>
  64. NaiveIRGenerator<T>::NaiveIRGenerator(const mnd::ir::Formula& irf,
  65. mnd::Precision prec) :
  66. mnd::MandelGenerator{ prec },
  67. form{ irf }
  68. {
  69. }
  70. template<typename T>
  71. struct EvalRes
  72. {
  73. size_t incVal;
  74. T result;
  75. };
  76. using namespace mnd;
  77. template<typename T>
  78. struct TVisitor
  79. {
  80. T a, b, x, y;
  81. size_t incrementValue;
  82. T visitNode(ir::Node* n) {
  83. EvalRes<T>* nodeData = getNodeData(n);
  84. if (nodeData) {
  85. if (nodeData->incVal == incrementValue)
  86. return nodeData->result;
  87. }
  88. T res = std::visit(*this, *n);
  89. if (nodeData) {
  90. nodeData->incVal = incrementValue;
  91. nodeData->result = res;
  92. }
  93. return res;
  94. }
  95. EvalRes<T>* getNodeData(ir::Node* n) {
  96. assert(n != nullptr);
  97. std::any& x = std::visit([](auto& n) -> std::any& {
  98. return n.nodeData;
  99. }, *n);
  100. if (auto* v = std::any_cast<EvalRes<T>>(&x))
  101. return v;
  102. else
  103. return nullptr;
  104. }
  105. T operator()(const ir::Constant& c) {
  106. return mnd::convert<double>(c.value);
  107. }
  108. T operator()(const ir::Variable& v) {
  109. if (v.name == "z_re")
  110. return a;
  111. else if (v.name == "z_im")
  112. return b;
  113. else if (v.name == "c_re")
  114. return x;
  115. else if (v.name == "c_im")
  116. return y;
  117. else
  118. return 0.0;
  119. }
  120. T operator()(const ir::Negation& n) {
  121. return -visitNode(n.value);
  122. }
  123. T operator()(const ir::Addition& n) {
  124. return visitNode(n.left) + visitNode(n.right);
  125. }
  126. T operator()(const ir::Subtraction& n) {
  127. return visitNode(n.left) - visitNode(n.right);
  128. }
  129. T operator()(const ir::Multiplication& n) {
  130. return visitNode(n.left) * visitNode(n.right);
  131. }
  132. T operator()(const ir::Division& n) {
  133. return visitNode(n.left) / visitNode(n.right);
  134. }
  135. T operator()(const ir::Atan2& n) {
  136. return ::atan2(visitNode(n.left), visitNode(n.right));
  137. }
  138. T operator()(const ir::Pow& n) {
  139. return ::pow(visitNode(n.left), visitNode(n.right));
  140. }
  141. T operator()(const ir::Cos& n) {
  142. return ::cos(visitNode(n.value));
  143. }
  144. T operator()(const ir::Sin& n) {
  145. return ::sin(visitNode(n.value));
  146. }
  147. T operator()(const ir::Exp& n) {
  148. return ::exp(visitNode(n.value));
  149. }
  150. T operator()(const ir::Ln& n) {
  151. return ::log(visitNode(n.value));
  152. }
  153. };
  154. template<typename T>
  155. void NaiveIRGenerator<T>::generate(const mnd::MandelInfo& info, float* data)
  156. {
  157. const MandelViewport& view = info.view;
  158. const bool parallel = true;
  159. T viewx = mnd::convert<T>(view.x);
  160. T viewy = mnd::convert<T>(view.y);
  161. T wpp = mnd::convert<T>(view.width / info.bWidth);
  162. T hpp = mnd::convert<T>(view.height / info.bHeight);
  163. #if defined(_OPENMP)
  164. if constexpr (parallel)
  165. omp_set_num_threads(omp_get_num_procs());
  166. # pragma omp parallel for schedule(static, 1) if (parallel)
  167. #endif
  168. for (long j = 0; j < info.bHeight; j++) {
  169. T y = viewy + T(double(j)) * hpp;
  170. long i = 0;
  171. for (i; i < info.bWidth; i++) {
  172. T x = viewx + T(double(i)) * wpp;
  173. TVisitor<T> beforeVisitor{ 0, 0, x, y, 0 };
  174. T a = beforeVisitor.visitNode(form.startA);
  175. T b = beforeVisitor.visitNode(form.startB);
  176. TVisitor<T> visitor{ a, b, x, y, 0 };
  177. int k = 0;
  178. for (k = 0; k < info.maxIter; k++) {
  179. T newA = visitor.visitNode(form.newA);
  180. T newB = visitor.visitNode(form.newB);
  181. a = newA;
  182. b = newB;
  183. if (a * a + b * b >= 16.0)
  184. break;
  185. visitor.incrementValue++;
  186. }
  187. data[i + j * info.bWidth] = float(k);
  188. }
  189. }
  190. }